Hibernate: MySQL error unknown column in having clause although column exists - java

I have a JPQL query in a repository that is the equivalent of the MySQL query below:
SELECT DISTINCT ji.* FROM tracker_job_item AS ji
JOIN tracker_work AS w ON ji.id=w.tracker_job_item_id
JOIN tracker_work_quantity AS wq on w.id=wq.tracker_work_id
WHERE w.work_type = 'CUTTING' AND ji.is_finished=0
GROUP BY wq.tracker_work_id
HAVING ji.quantity != SUM(wq.received_quantity)
The MySQL version works just fine, but the JPQL equivalent gives an exception: Unknown column 'jobitem0_.quantity' in 'having clause'
The JPQL query is like below:
#Query("select distinct ji from JobItem ji" +
" join Work w on ji.id=w.jobItem.id" +
" join WorkQuantity wq on w.id=wq.work.id" +
" where w.workType='CUTTING' and ji.isFinished=false and ji.jobItemName like %:search%" +
" group by ji.id" +
" having ji.quantity != sum(wq.receivedQuantity)")
Page<JobItem> findAllActiveCuttingJobs(Pageable pageable, #Param("search") String search);
Please help me with why I'm getting the error even though the field quantity exists in JobItem.

You can't reference a column in the having clause that isn't in the group by clause, definitely in JPA and (normally at least) in SQL. Looks like MySQL is letting you get away with it but JPA isn't.
See here:
http://learningviacode.blogspot.co.uk/2012/12/group-by-and-having-clauses-in-hql.html

Related

jpa order records descending and select first record

I have a spring boot app connected to oracle DB.
I am trying to order a list of records and select the top most record.
I wrote a JPA query as below but it fails.
#Query("SELECT id FROM UploadedFile uploadedFile "
+ "WHERE uploadedFile.p_file_type = 'branch' "
+ "and p_file_status='Processed' "
+ "and p_is_file_process_with_error = 0 "
+ "order by c_created_date desc "
+ "FETCH FIRST 1 rows only ")
public String findLatestBranchCodeFile();
The error received was
creating bean with name 'uploadedFileRepo': Invocation of init method
failed; nested exception is java.lang.IllegalArgumentException:
Validation failed for query for method public abstract
java.lang.String
com.rhb.pintas.repo.UploadedFileRepo.findLatestBranchCodeFile()!
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token:
FETCH near line 1, column 204 [SELECT id FROM
com.rhb.pintas.entities.UploadedFile uploadedFile WHERE
uploadedFile.p_file_type = 'branch' and p_file_status='Processed' and
p_is_file_process_with_error = 0 order by c_created_date desc FETCH
FIRST 1 rows only ] -> [Help 1]
The issue seems to be with fetch,not sure whats wrong.
It seems you are mixing HQL and native query dialects:
If this will be a naviveQuery (like most of the columns would mention), then replace the entity name with table name and add nativeQuery option. And because You are using only a single table, You can skip the alias name:
#Query("SELECT id FROM uploaded_file "
+ "WHERE p_file_type = 'branch' and p_file_status='Processed' and "
+ "p_is_file_process_with_error = 0 "
+ "order by c_created_date desc "
+ "FETCH FIRST 1 rows only ", nativeQuery = true)
public String findLatestBranchCodeFile();
If You want to keep it as a HQL, then replace all column names with entity property names, like p_file_type > fileType (I guess column names). Secondly You will need to pass a Pageable parameter, to replace Your 'Fetch first' statement.
You can find more materials here:
Bealdung
NativeQ
StackOverflow
You are trying to execute SQL query, in this case you need to add nativeQuery=true attribute to #Query annotation
UPD.
got confused because FETCH FIRST - is a SQL syntax, for JPA way please check another solution - it is possible to return list with at most one element.
I guess, you can try passing pagable to limit result set size and unlimit your query:
public String findLatestBranchCodeFile(Pageable pageable); // pass new PageRequest(0,1)

Spring JPA query with clause "where value in (select id from otherTable)"

I want to write a JPA query that extracts all my entities matching a simple condition (column=boolean value) and a more complex conditions, i.e. the entity ID shall be contained in another table. MyEntity has no relationship with this other table.
My not working guess is:
#Query(value =
"select msr " +
"from MyEntity msr " +
"where msr.archived=false " +
" AND msr.id in
(select sc.res from search_campaign_results sc
where search_campaign_id=:campaign)")
Page<MyEntity> findResultsNotAnalyzed(Pageable pr, #Param("campaign") Long campaign);
Of course the error is "search_campaign_results is not mapped", which is correct .
How can I fix this without writing a completely native query?

Hibernate expecting "all", found '(' - what does this mean?

I'm getting this error and I can't find any reference to it:
org.hibernate.hql.internal.ast.QuerySyntaxException: expecting "all", found '(' near line 1, column 221 [select new EffectivePermissions(r.id, r.name, r.defaultValue, rc.value AS companyValue, ru.value AS userValue) from permissionsPackage.Entity.Permissions r left join permissionsPackage.Entity.CompanyPermissions rc fetch (r.id=rc.permissionId AND rc.companyId=2313 ) left join permissionsPackage.Entity.UserPermissions ru fetch (r.id=ru.permissionId AND ru.userId=1)]
at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:54)
at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:47)
at org.hibernate.hql.internal.ast.ErrorCounter.throwQueryException(ErrorCounter.java:79)
Below is the Query I'm using.
this.hql = "select new EffectivePermissions(r.id, r.name, r.defaultValue, rc.value AS companyValue, ru.value AS userValue) "
+ "from "
+ Permissions.class.getName()
+ " r "
+ "left join "
+ CompanyPermissions.class.getName()
+ " rc "
+ "fetch (r.id=rc.permissionId AND rc.companyId="
+ user.getCompany().getId()
+ " ) "
+ "left join "
+ UserPermissions.class.getName()
+ " ru "
+ "fetch (r.id=ru.permissionId AND ru.userId="
+ user.getId()
+ ")";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
permissions = query.list();
I have a class called EffectivePermission with the properties in the constructor and I'd like to get a list based on it.
From the Hibernate Reference chapter 14.3. Associations and joins:
A "fetch" join allows associations or collections of values to be initialized along with their parent objects using a single select ... See Section 19.1, “Fetching strategies” for more information.
You'll also see there that it must be used after the joinkeyword as in from e1 left join fetch e2. It can also be used as in from entity fetch all properties (this is why Hibernate is expecting the all keyword).
Regarding your specific query, and as far as I know, with HQL you can not specify the join conditions. Hibernate will automatically perform the join using the conditions configured in the mapping. This is why it is necessary to have relationships mapped in order to use a HQL join.
And most importantly, remember that joins in HQL are quite different. You don't join two entities, you join an entity with one of its collection-valued properties (associations). Notice you can always do cartesian-like joins (pay attention to performance and always look at the generated queries and execution plans).
As a side note, it can be considered bad practice to append parameter values directly into the query (due to potential injection vulnerabilities). You should be using named parameters instead.

Group by in HQL and Hibernate Criteria queries (ORA-00979: not a GROUP BY expression)

I am new to new to hibernate and Java, so I apologize if these are ridiculously simply questions.
I don't understand why the following query gives me the error "ORA-00979: not a GROUP BY expression".
Query q = session.createQuery (
"select new tdata.Summary(tbForm.rYear, SUM(tbForm.pWaste)) "
+ "from TrForm tbForm "
+ "left join fetch tbForm.indKey "
+ "where tbForm.indKey.grpCode='999' "
+ "group by tbForm.rYear " );
The possible reasons for this error do not seem to apply to my query because I am including group by function SUM, and I do not have any expressions in the select that are not in the group by.
I also tried to write a criteria query to do what I need, and I could not get that to work either. In the criteria version, I am confused as to how to add restrictions to fetched data and how to get the data into the Summary object.
Criteria criteria = session.createCriteria(TrForm.class)
.setFetchMode("DimInd",FetchMode.JOIN)
.add(Restrictions.eq("indKey.indCode", "999"))
.setProjection(Projections.projectionList()
.add(Projections.groupProperty("rYear"))
.add(Projections.sum("pWaste")));
summaryList = (List<Summary>) criteria.list();
Any help would be greatly appreciated.
Thanks!
Update:
Thank you so much! I removed the "left join fetch tbForm.indKey" and the HQL version worked!
Generalized query is
select R_YEAR, sum(P_WASTE)
from TR_FORM tbForm
left join DIM_IND ind
on tbForm.IND_KEY = ind.IND_KEY
where ind.GRP_CODE='999'
group by tbForm.R_YEAR
tdata is the folder in which I have the java code for the data models.

Hibernate #Formula is not supporting query contains 'CAST() as int' function

Following is the one of property of ExecutionHistory class, which value is fetched from
#Formula using JPA/Hibernate from exectution_history table,
#Formula("(SELECT SUM(dividend) || '/' || SUM(divisor) " +
"FROM (SELECT CAST(substr(sr.result, 1, position('/' in sr.result)-1 ) AS int) AS dividend ," +
"CAST(substr(sr.result, position('/' in sr.result)+1 ) AS int) AS divisor " +
"FROM suite_results as sr WHERE sr.execution_history=id) AS division)")
private String result;
When I tried to get instance of ExecutionHistory class, I found that above formula query
is converted by JPA/Hibernate like this:
select executionh0_.id as id7_1_, executionh0_.execution_plan as execution3_7_1_, executionh0_.start_time as start2_7_1_,
(SELECT SUM(sr.duration) FROM suite_results as sr WHERE sr.execution_history=executionh0_.id) as formula0_1_,
(SELECT SUM(executionh0_.dividend) || '/' || SUM(executionh0_.divisor) FROM
(SELECT CAST(substr(sr.result, 1, position('/' in sr.result)-1 ) AS executionh0_.int) AS executionh0_.dividend ,
CAST(substr(sr.result, position('/' in sr.result)+1 ) AS executionh0_.int) AS executionh0_.divisor
FROM suite_results as sr WHERE sr.execution_history=executionh0_.id) AS executionh0_.division) as
formula1_1_, executionp1_.id as id6_0_, executionp1_.build_number as
build2_6_0_, executionp1_.name as name6_0_, executionp1_.owner as owner6_0_, executionp1_.sut as sut6_0_,
executionp1_.wait_for_page_to_load as wait6_6_0_ from execution_history executionh0_
left outer join execution_plans executionp1_ on executionh0_.execution_plan=executionp1_.id where executionh0_.id=?
So the problem is that, here formula query contains "CAST() AS int", but during query conversion by Hibernate, it puts unnecessary table reference and execute it as "CAST() AS executionh0_.int" so it giving sql grammer exeception while execution.
I've no idea about how to avoid this problem, Can anybody help me in this?
Thanks.
It's an old question, but I'll post an answer anyway.
If you are using a SQL Server database, you can add double quotes around the type you are casting.
Something like this:
#Formula("CAST(FLOOR(CAST( dat_criacao AS \"float\")) AS \"datetime\")")
Don't know which database you're using, but in SQL Server you should use CONVERT rather than CAST in you Hibernate queries.

Categories