Hibernate Inner Join OneToMany Mapping throws HibernateQueryException - java

I am new to Hibernate. I have established a OneToMany mapping between User and Expense. I am trying to return expenses for a User for the last week.
This is the MySQL query that I am using.
select SUM(amount) from Expense INNER JOIN User ON Expense.user_id = User.id AND User.username ='testUser' WHERE created >= curdate() - INTERVAL DAYOFWEEK(curdate())+1 DAY AND created < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY;
When I try to use this query in hibernate, I get a HibernateQueryException
String query = "select SUM(amount) from Expense INNER JOIN User ON Expense.user_id = User.id AND user.username ='sarvam' WHERE created >= curdate() - INTERVAL DAYOFWEEK(curdate())+1 DAY AND created < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY";
List list = session.createQuery(query).list();
The error I get is-
Exception in thread "main" org.hibernate.QueryException: outer or full join must be followed by path expression [select SUM(amount) from com.challenge.pojo.Expense INNER JOIN User ON Expense.user_id = User.id AND user.username ='sarvam' WHERE created >= curdate() - INTERVAL DAYOFWEEK(curdate())+1 DAY AND created < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY]
at org.hibernate.QueryException.generateQueryException(QueryException.java:120)
at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:103)
at org.hibernate.hql.internal.classic.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:233)
at org.hibernate.hql.internal.classic.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:193)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:76)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:150)
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:298)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:236)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1825)
at com.challenge.dao.ExpenseDAO.getExpensesForLastWeek(ExpenseDAO.java:52)
at com.challenge.dao.ExpenseDAO.getExpensesForLastWeek(ExpenseDAO.java:44)
at com.challenge.dao.Test.main(Test.java:27)
Caused by: org.hibernate.QueryException: outer or full join must be followed by path expression
at org.hibernate.hql.internal.classic.FromParser.token(FromParser.java:253)
at org.hibernate.hql.internal.classic.ClauseParser.token(ClauseParser.java:93)
at org.hibernate.hql.internal.classic.PreprocessingParser.token(PreprocessingParser.java:118)
at org.hibernate.hql.internal.classic.ParserHelper.parse(ParserHelper.java:43)
at org.hibernate.hql.internal.classic.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:223)
... 10 more
Can anyone please help me fix it.

createQuery(String queryString) Create a new instance of Query for the
given HQL query string.
createSQLQuery(String queryString)
Create a new instance of SQLQuery for the given SQL query string.
You're using the first one which expects HQL as an input, for using native SQL you sould use the second one.
String query = "select SUM(amount) from Expense INNER JOIN User ON Expense.user_id = User.id AND user.username ='sarvam' WHERE created >= curdate() - INTERVAL DAYOFWEEK(curdate())+1 DAY AND created < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY";
List list = session.createSQLQuery(query).list();
Session Documentation

You might want to take a look at: I can't make a inner join between two tables in hibernate hql query
If using HQL you have to their Object-Oriented style which might look something like this:
String query = "select SUM(amount) from Expense exp INNER JOIN User u ON e.user_id = u.id AND u.username = 'sarvam' ...";
List list = session.createQuery(query).list();
(untested)
Alternatively you can keep using standard SQL syntay if you instead use:
List list = session.createSQLQuery(query).list();
Then you might want to read Chapter 16 of the Hibernate Documentation.
Keep in mind that the SQL dialect depends on the underlying Database. Depending on your Application there might be a different database used on a different system which could break your SQL statements.

Related

Adding X hours - #Query - Spring Data JPA

I have tried make a different method in Spring Data JPA Repository which should adding the given hours to timestamp.
public interface ActivationCodeRepository extends CrudRepository<ActivationCode, Long> {
#Query(value = "select a from ActivationCode a where a.creationTime + INTERVAL '1 hour' * :hoursAgo <= CURRENT_TIMESTAMP and a.type = :type and a.account = account")
List<ActivationCode> getAllAddedAtLeastXHoursAgo(#Param("account") Account account, #Param("type") int type, #Param("hoursAgo") int hoursAgo);
}
It is not working because of it:
INTERVAL '1 hour' * :hoursAgo
exactly:
'1 hour'
The IDE underscores and given this error:
<'expression'>, <'operator'>, GROUP, HAVING or ORDER expected.
I have tried do some research and find how exactly I should adding the given hours to the creationTime but not found anywhere.
I don't believe PostgreSQL allows passing the INTERVAL statements require a hard-coded string with an interval '1 day'-style input; however you can achieve this by casting a string to an interval.
Try changing the SQL query in your code to:
select a from ActivationCode a where a.creationTime + (:hoursAgo||' hour')::interval <= CURRENT_TIMESTAMP and a.type = :type and a.account = account
Alternatively, I've just found this previous StackOverflow answer, this would be worth a try but might have the same issue (presuming it's related to Spring Data JPA's query parser):
select a from ActivationCode a where a.creationTime + :hoursAgo * INTERVAL '1 hour' <= CURRENT_TIMESTAMP and a.type = :type and a.account = account
Like a_horse_with_no_name said I had to use native query to do something like that so I changed my method to:
#Query(value = "select * from activation_codes a where a.type = :type and a.id_account = :id_account and a.creation_time <= NOW() - :hoursAgo * INTERVAL '1 hour'", nativeQuery = true)
List<ActivationCode> getAllAddedAtLeastXHoursAgo(#Param("id_account") int id_account, #Param("type") int type, #Param("hoursAgo") int hoursAgo);
And it works correct.
Thanks for all help.
If anyone is interested after all this time, I did this in the most despicable way possible. But it worked.
The #Query Annotation is like below;
#Query("SELECT q FROM QueryStatusDao q WHERE q.jobStatus='Submit' AND q.submitTime < now() - :interval")
List<QueryStatusDao> getRunnableParkedQueries(#Param("interval")String interval);
And I call this method like this;
queryStatusRepository.getRunnableParkedQueries("INTERVAL '1 hour'");
If I find any other non-despicable method to do this, I will update.

Hibernate query not returning Zero value

Same query working in SQL
Select count(tbl_leads.lead_Status_Id) , tbl_LeadStatus.LeadStatus_Type FROM tbl_LeadStatus LEFT JOIN tbl_leads ON tbl_LeadStatus.LeadStatus_id = tbl_leads.lead_Status_Id GROUP BY tbl_LeadStatus.LeadStatus_Type;
Hibernate Query
Select s.LeadStatus_Type, count(l.status) FROM Status s "
+ "LEFT JOIN Lead l ON l.status = s.LeadStatus_id "
+ "GROUP BY s.LeadStatus_Type"
Expecting output is this
Count LeadStatus_Type
'0' 'Cancelled'
'0' 'In-Progress'
'1' 'New'
'0' 'Sold'
'0' 'UnAssigned'
And HQL return this
'1', 'New'
Your join condition looks off. In HQL we join from an entity to the other entity which exists as a property of the first entity. Most importantly, there is no ON clause as that relationship is already known within Hibernate. Try the following:
SELECT s.LeadStatus_Type, COUNT(l.status)
FROM Status s
LEFT JOIN s.LeadStatus_id l
GROUP BY s.LeadStatus_Type

JPA count query with maximum results

Can you please share me code snippet to be written via JPA in order to generate the below sql query
SELECT COUNT(*) FROM Customer c
WHERE c.countryId ='Canada' AND
c.lanuguage ='ENG' AND
ROW_NUM <=10;
Because I tried in the below way. But MaxResults is not getting applied it seems as I can able to recieve the count more than 10.
Query query = em.createQuery("SELECT COUNT(c) FROM Customer c where c.countryId ='Canada' and c.lanuguage ='ENG'");
query.setMaxResults(10);
long customerCount = (Long)query.getSingleResult();
Select on count will always return a single value. If you want to have a count lower than 10, add HAVING.
SELECT COUNT(c) AS
FROM Customer c
WHERE c.countryId='Canada' and c.language='END'
HAVING COUNT(c)<=10

How to write query to compare difference between two timestamps with a timeinterval

I am trying to pull out records based on some comparison between two timstamps. here is my supposed code, but it is not working:
#Query("SELECT n FROM table1 n WHERE n.status IN ('FAILED') AND :currentDate- n.updatedDate > n.interval/24*60*60")
List<Entity> findAllSuchEntities(#Param("currentDate") DateTime currentDate);
The error message is : org.h2.jdbc.JdbcSQLException: Unknown data type: "?"; SQL statement.
In comparison, following query can pass compilation:
#Query("SELECT n FROM table1 n WHERE n.status IN ('FAILED') AND :currentDate > n.updatedDate")
List<Entity> findAllSuchEntities(#Param("currentDate") DateTime currentDate);
Try this:
#Query("SELECT n FROM table1 n WHERE n.status IN ('FAILED') AND n.updatedDate < (:currentDate - (n.interval/24*60*60))")
It is also a better solution as your previous query will most likely cause a full table scan.

dynamic variable value jasper report

I don't know how to title this question and I know it's just a simple and stupid logic need to be sorted out but I can explain what I need. I have a jasper report script and query in which I need a simple calculation based on a value gathered from Query below
SELECT TOTAL, PARTIAL FROM PRICE WHERE TOTAL > 0
now I need this value to be calculated as the expression below in jasper report script
VAR CALC += TOTAL + (PARTIAL) //as partial can be a -ve or +ve value
What's happening currently is that I didn't find a way to do this, whenever I assign value of TOTAL to a variable and try to use it, it always get's the value from Query and calculates, while I need it to be there only once and then perform calculation on it onward. For that I tried to use calculation="First" but that also gives the first value for all the time and continues. I hope I am able to put my problem well, please help
EDIT
QUERY
SELECT RECEIPTS.DATENEW AS DATE,
TICKETS.TICKETID AS TICKETID,
PAYMENTS.PAYMENT AS PAYMENT,
PAYMENTS.METHOD AS METHOD,
PAYMENTS.TOTAL AS TOTAL,
CUSTOMERS.NAME AS NAME,
(SELECT SUM(P.TOTAL) FROM PAYMENTS AS P
INNER JOIN RECEIPTS AS R ON P.RECEIPT = R.ID
INNER JOIN TICKETS AS T ON R.ID = T.ID
INNER JOIN CUSTOMERS AS C ON T.CUSTOMER = C.ID
WHERE C.ID = CUSTOMERS.ID and P.PAYMENT IN ('debt','debtpaid', 'advance', 'cashrefund')) AS CTOTAL
FROM RECEIPTS
INNER JOIN TICKETS ON RECEIPTS.ID = TICKETS.ID
INNER JOIN PAYMENTS ON RECEIPTS.ID = PAYMENTS.RECEIPT
INNER JOIN CUSTOMERS ON TICKETS.CUSTOMER = CUSTOMERS.ID
WHERE
PAYMENTS.PAYMENT IN ('debt', 'debtpaid', 'advance', 'cashrefund')
....
....
WHERE -TOTAL > 0
VARIABLE
<variable name="DUES" class="java.lang.Double" resetGroup="Customer" resetType="Group" calculation="Nothing">
<variableExpression><![CDATA[$F{CTOTAL} + $F{TOTAL}]]></variableExpression>
<initialValueExpression><![CDATA[new Double(0.0)]]></initialValueExpression>
</variable>
OUTPUT
You can define the variable itself in SQL statement like this :-
SELECT SUM(#csum := #csum + TOTAL+PARTIAL)
FROM (SELECT TOTAL, PARTIAL,#csum := 0
FROM PRICE WHERE TOTAL > 0
) a;
See this question and answer

Categories

Resources