Postgres Interval not working with native spring data JPA query - java

I have created a native query with interval. The query works fine when i hard code day in query:
#Query(value="select * from orders where created_date < clock_timestamp() - interval ' 5 days'",nativeQuery=true)
But when i provide data with #Param like this:
#Query(value="select * from orders where created_date < clock_timestamp() - interval :day 'days'",nativeQuery=true)
List<Order> getData(#Param("day") String day)
I got this error:
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at
or near "$1"

You can't provide a value for an interval like that. You need to multiple the parameter value with your interval base unit:
"select * from orders
where created_date < clock_timestamp() - (interval '1' day) * :days"
As you are dealing with days, you can simplify that to:
"select * from orders
where created_date < clock_timestamp() - :days"
Another option is the make_interval() function. You can pass multiple parameters for different units.
"select * from orders
where created_date < clock_timestamp() - make_interval(days => :days)"
The notation days => ... is a named parameter for a function call. If the variable represents hours, you could use make_interval(hours => ..)

One solution is provided in this entry Spring Boot Query annotation with nativeQuery doesn't work in Postgresql
Basically:
#Query(value="select * from orders where created_date < clock_timestamp() - ( :toTime )\\:\\:interval",nativeQuery=true)
'toTime' is a Param from your repository and could be days, hour, minute... etc(review interval doc in Postgres) #Param("toTime") String toTime

Related

how to generate random timestamp in sql query withing range for h2 database?

I have this db table in an H2 database called "mytable" and two of the fields have the type "TIMESTAMP".
I have writen the following query in order to update the table:
UPDATE mytable
SET START_TIME_ = "2018-01-01 01:01:01" , END_TIME_ = "2020-01-01 01:01:01";
I was wondering how could I modify my query so that it generates at the START_TIME_ and END_TIME_ fields random dates between 2018-01-01 01:01:01 and 2020-01-01 01:01:01. As the H2 timestamp is not a UNIX timestamp I am unsure how to go about it. I appreciate any help you can provide.
In H2 1.4.200 you can use
UPDATE mytable SET
START_TIME_ = #T := TIMESTAMP '2018-01-01 01:01:01'
+ RAND() * INTERVAL '730 00:00:00' DAY TO SECOND,
END_TIME_ = #T + (TIMESTAMP '2020-01-01 01:01:01' - #T) * RAND();
INTERVAL '730 00:00:00' DAY TO SECOND can be replaced with the subtraction operation between high and low bounds (TIMESTAMP '2020-01-01 01:01:01' - TIMESTAMP '2018-01-01 01:01:01').
Note that distribution of START_TIME_ is linear here, but distribution of END_TIME_ is not. If such distribution doesn't satisfy your needs, you need to use some more complex expressions, but you can use the same datetime arithmetic operations in them.
Please also note that inline variable assignment syntax uses the := operator and not the = operator.

Substract years from current_date in JPQL

I want to delete the rows which are older than 2 years. In SQL I do it like this:
DELETE FROM table WHERE creation_date < (current_date - interval '2 year');
Now I want to do the same for my JPA Repository in Java with the JPQL.
In JPQL I get an error because interval is not known and the "-"(minus) is not correct.
JPQL Query
#Query("DELETE FROM table t WHERE t.creation_date < (current_date - interval '2 year')")
I would appreciate any suggestion.
You can calculate the dateTime in the application, assuming you are using LocalDateTime for creation_date
LocalDateTime dateTime = LocalDateTime.now().minus(Period.ofYears(2));
and pass the parameter in JPQL
#Query("DELETE FROM table t WHERE t.creation_date < :dateTime")
void deleteByDateTime(LocalDateTime dateTime)

H2 org.h2.jdbc.JdbcSQLSyntaxErrorException when inserting a Timestamp

A SQL query comparing timestamps works in MySQL, but fails when using an H2 database.
As an example, this is the query that produces the exception:
SELECT * FROM table WHERE time >= '2019-02-01T10:59:12.632Z' AND time <= '2019-04-12T10:59:12.632Z'
The query is created dynamically using Java code, and the timestamps above are of type java.time.Instant.
I have even tried using other types of date/time objects, with the same outcome.
This query executes fine using MySQL, but throws the following error using an H2 DB:
org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement
"SELECT * FROM table WHERE time>= 2019-04-10T13[*]:31:19.498Z AND time <= 2019-04-07T13:31:19.498Z";
SQL statement:
SELECT * FROM table WHERE time >= 2019-04-10T13:31:19.498Z AND time<= 2019-04-07T13:31:19.498Z
I find it puzzling that using colon-separated timestamps cause this issue, especially since the H2 docs use similar timestamps
try converting date string properly
SELECT * FROM table WHERE time >= str_to_date('2019-02-01 10:59:12.632 ', '%Y-%m-%d %T.%f')
AND time <= str_to_date( '2019-04-12 10:59:12.632 ' , '%Y-%m-%d %T.%f')
I am using Spring Boot's JdbcTemplate and creating my queries as follows:
jdbcTemplate.query("SELECT * FROM table WHERE time >= " + startTime + " AND " + " time <= " + endTime, (rs, i) -> Accessor.readFromResultSet(rs));
with the date Strings passed in as Instant objects.
The solution, thanks to #OleV.V's comment, was to pass the date objects in as an Object argument:
jdbcTemplate.query("SELECT * FROM table WHERE time >= ? AND time <= ?", new Object[]{startTime, endTime}, (rs, i) -> Accessor.readFromResultSet(rs));

How to write a complex SQL query in query DSL

I try to calculate percentage of amout of a specific product per total amout of products. I wrote a SQL query that works fine.
But when i try to write in Query DSL I encountred a problem , i really have a problem to write this kind of query.
SELECT ROUND((c.v2/f.v1)*100,2) , MONTH AS RESULTt
FROM
(SELECT SUM(Quantite)as v1,MONTH FROM Total_sold_view WHERE id_company='379' AND
year=2009 GROUP BY MONTH ORDER BY MONTH ASC) f,
(SELECT Quantite as v2,MONTH FROM Total_sold_view WHERE id_company='379' AND year=2009
AND product_type=13 ORDER BY MONTH ASC) c
WHERE c.MONTH=f.MONTH

How to construct advanced Hibernate Query with OR and summarize functions

I have a rather complex query which works in SQL, but I would like to express this in HQL for portability. I'm going to fetch a user configured preference value if they exist, if not I must use a default value. This value must be subtracted from current date and the matched against a column in the table which I'm interested in:
select d.id, d.guid, d.deletetimestamp, u.id
from descriptor d, ownerkey ow, user u
where
d.parentid in
(select td.id
from descriptor td, store s
where s.type = 'Trash'
and s.descriptorid = td.id
)
and d.ownerkeyid = ow.id
and ow.ownerid = u.id
and
(
(d.deletetimestamp < CURRENT_TIMESTAMP() - INTERVAL
(select pv.value
from preferencevalue pv, userpreference up
where u.id = up.userid
and up.preferenceid = 26
and up.value = pv.id)
DAY)
or
(d.deletetimestamp < CURRENT_TIMESTAMP() - INTERVAL
(select cast(pv.value as SIGNED)
from preferencevalue pv, defaultpreference dp
where dp.preferenceid = 26
and not exists(select up.userid from userpreference up where u.id = up.userid and up.preferenceid = 26)
and dp.value = pv.id)
DAY)
)
I'm trying to construct this by using the Criteria API which seems to include most of the logical operators that I need (equals, larger than, or, isEmpty/isNull), but not sure how I would express all these parts.
Using a view is not an option at this point since we're using MySQL as the production database while the integration tests are running with H2 inmemory database. I'm not able to get find the sata substract function in H2 while MySQL do support this.
The select fields isn't important since they have only been used for testing purposes.
you can use Restrictions.disjunction() for or -and Restrictions.conjuction() for and clauses.
To reference a certain property of an entity (like pv.value) you can use Projections.property("value")
for the casting I'm not sure, perhaps using the #Formula annotation on your entity? But this is a hibernate and not a JPA annotation.
as far as I know there is no equivalent for INTERVAL in hibernate but in such cases (maybe also for the above cast) you could use Restrictions.sqlRestriction("some sql...")
It will be a challenge putting all of this together to transform your query to hibernate criteria.
greetz,
Stijn

Categories

Resources