Adding X hours - #Query - Spring Data JPA - java

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.

Related

Hibernate Inner Join OneToMany Mapping throws HibernateQueryException

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.

Select order by random() Query not working in Java

I'm using a query in my repository and i'm trying to select 10 random questions from a table. but I get this error
ASC or DESC expected got '('
and i have no idea why
#Query ( value = "select q from Question q where q.chapitre_id=:id order by
random() limit 10", nativeQuery = true)
List<Question> findQuestionsByChapitre(#Param("id") Long id);
First of all, ordering by 1, 2, 3 or whatever number means ordering by the column in the corresponding position; if you only select one column (q in your case) you will be able to order only by that (it may work in older versions though).
Then, the correct syntax for ordering by a casual value is order by rand()
This is what worked for me :
#Query ( value = "select * from question q where q.chapitre_id=:id order
by rand() limit 10", nativeQuery = true)
Question[] findQuestionsByChapitre(#Param("id") Long id);

queryDSL returns one record if limit and offset provided

I am using queryDSL JPA.
I am trying to load data in chunks, so I am using .offset() and .limit()
I am querying 'single_entry' table, that contains 10000 records.
I use the following function to query data
private Collection<SingleEntry> getSingleEntries(FiscalPeriod fp, Predicate filter, Integer offset, Integer limit) {
BooleanExpression initialFilter = getSingleEntriesFilter(fp);
return query.selectFrom(QSingleEntry.singleEntry).where(initialFilter.and(filter)).offset(offset).limit(limit).fetch();
}
private BooleanExpression getSingleEntriesFilter(FiscalPeriod fp) {
int period = fp.getPeriod();
int year = fp.getYear();
QSingleEntryModification sem = QSingleEntryModification.singleEntryModification;
QSingleEntry se = QSingleEntry.singleEntry;
BooleanExpression fiscalPeriodMatches = se.year.eq(year).and(se.period.loe(period));
//excludes single entries that moved from this period
BooleanExpression excludeMoved = se.documentNumber.notIn(query.selectDistinct(sem.documentNumber).from(sem)
.where(sem.moved.eq(true)
.and(sem.originYear.eq(year)
.and(sem.originPeriod.loe(period)).and(sem.movedToPeriod.gt(period).or(sem.movedToYear.ne(year))))));
BooleanExpression movedToPeriodOrNonMoved = se.documentNumber.in(query.selectDistinct(sem.documentNumber).from(sem)
.where(sem.moved.eq(false).and(sem.originYear.eq(year).and(sem.originPeriod.loe(period))).or(sem.movedToPeriod.loe(period).and(sem.movedToYear.eq(year)))));
return fiscalPeriodMatches.and(excludeMoved).or(movedToPeriodOrNonMoved);
}
Hibernate produces the following query when offset equals 0 and limit are set:
select
* //replaced with * to be concise
from
single_entry singleentr0_
where
(
singleentr0_.year=?
and singleentr0_.period<=?
and (
singleentr0_.document_number not in (
select
distinct TOP(?) singleentr1_.document_number
from
single_entry_modification singleentr1_
where
singleentr1_.moved=?
and singleentr1_.origin_year=?
and singleentr1_.origin_period<=?
and (
singleentr1_.moved_to_period>?
or singleentr1_.moved_to_year<>?
)
)
)
or singleentr0_.document_number in (
select
distinct singleentr2_.document_number
from
single_entry_modification singleentr2_
where
singleentr2_.moved=?
and singleentr2_.origin_year=?
and singleentr2_.origin_period<=?
or singleentr2_.moved_to_period<=?
and singleentr2_.moved_to_year=?
)
)
and singleentr0_.account_number=?
This query return one result, however, if I run this query in a database manager, it returns a correct number of results.
If the offset is non-zero and the limit is set Hibernate generates following query:
WITH query AS (SELECT
inner_query.*,
ROW_NUMBER() OVER (
ORDER BY
CURRENT_TIMESTAMP) as __hibernate_row_nr__
FROM
( select
* //replaced with * to be concise
from
single_entry singleentr0_
where
(singleentr0_.year=?
and singleentr0_.period<=?
and (singleentr0_.document_number not in (select
distinct singleentr1_.document_number
from
single_entry_modification singleentr1_
where
singleentr1_.moved=?
and singleentr1_.origin_year=?
and singleentr1_.origin_period<=?
and (singleentr1_.moved_to_period>?
or singleentr1_.moved_to_year<>?)))
or singleentr0_.document_number in (select
distinct singleentr2_.document_number
from
single_entry_modification singleentr2_
where
singleentr2_.moved=?
and singleentr2_.origin_year=?
and singleentr2_.origin_period<=?
or singleentr2_.moved_to_period<=?
and singleentr2_.moved_to_year=?))
and singleentr0_.account_number=? ) inner_query ) SELECT
* //replaced with * to be concise
FROM
query
WHERE
__hibernate_row_nr__ >= ?
AND __hibernate_row_nr__ < ?
that query returns the correct number of results.
I have 2 questions:
1. why the first query returns only 1 result?
2. why in the first query TOP(?) appears not in top level select but in subquery?
Please let me know if additional source code should be provided
Thank you!

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.

Categories

Resources