Java query for postgresql's interval method not working - java

I'm writing postgresql query. When I run the query
"reservatio0_.DATE_ >(NOW() - '60 MINUTES'::INTERVAL)" on pgAdmin it works fine, but in java I get
QuerySyntaxException, unexpected token: : bla bla
if I run this code
List<Reservation> list = em.createQuery(
"select r " +
"from Reservation r " +
"where r.group.id=:groupName " +
" and r.date >(NOW() - '60 MINUTES'::INTERVAL) " +
"order by r.date asc")
.setParameter("groupName", groupName)
.setParameter("number", number)
.setMaxResults(1)
.getResultList();

try to replace your colon operator (:) with \\:
that would escape this special character..

IIrc you have to put the interval in front of the amount, like this:
and r.date >(NOW() - interval '60 minutes')

Related

JPA parameter outside a where clause

I would like to know if the is a way to build a JPA query with parameter outside of the where clause. This query works fine in my database manager.
There is my query :
#Query(value = "SELECT q.quote, q.author, q.display_at, count(ql.*) AS like, (SELECT '{:userUUID}'::uuid[] && ARRAY_AGG(ql.user_uuid)::uuid[]) AS liked " +
"FROM quotes q " +
"LEFT JOIN quotes_likes ql ON ql.quote_uuid = q.uuid " +
"WHERE display_at = :date " +
"GROUP BY q.quote, q.author, q.display_at;", nativeQuery = true)
Optional<QuoteOfTheDay> getQuoteOfTheDay(UUID userUUID, LocalDate date);
I have the following error when the query is called : ERROR: syntax error at or near ":"
By default, Spring Data JPA uses position-based parameter binding. We can also use named parameter with #Param annotation to give a method parameter a concrete name and bind the name in the query. As you are trying to use the named parameter try using the below snippet with #Param annotations.
Optional<QuoteOfTheDay> getQuoteOfTheDay(#Param("userUUID") UUID userUUID, #Param("date") LocalDate date);
ERROR: syntax error at or near means that you need to escape casting colons.
Every : needs to be replaced by \\:
(SELECT ARRAY[:userUUID]'\\:\\:uuid[] && ARRAY_AGG(ql.user_uuid)\\:\\:uuid[]) AS liked
OR use double colons
(SELECT ARRAY[:userUUID]::::uuid[] && ARRAY_AGG(ql.user_uuid)::::uuid[]) AS liked
OR use Cast instead of colons
(SELECT cast(ARRAY[:userUUID] as uuid[]) && cast(ARRAY_AGG(ql.user_uuid) as uuid[])) AS liked
The second problem is that you need to create an array with a query parameter.
Try ARRAY[:userUUID] instead of {:userUUID}
Full query example:
#Query(value = "SELECT q.quote, q.author, q.display_at, count(ql.*) AS like, (SELECT ARRAY[:userUUID]\\:\\:uuid[] && ARRAY_AGG(ql.user_uuid)\\:\\:uuid[]) AS liked " +
"FROM quotes q " +
"LEFT JOIN quotes_likes ql ON ql.quote_uuid = q.uuid " +
"WHERE display_at = :date " +
"GROUP BY q.quote, q.author, q.display_at;", nativeQuery = true)
Optional<QuoteOfTheDay> getQuoteOfTheDay(UUID userUUID, LocalDate date);
As you are trying to pass method parameters to the query using named parameters, We define these using the #Param annotation inside our repository method declaration.
Each parameter annotated with #Param must have a value string matching the corresponding JPQL or SQL query parameter name.
#Query(value = "SELECT q.quote, q.author, q.display_at, count(ql.*) AS like, (SELECT '{:userUUID}'::uuid[] && ARRAY_AGG(ql.user_uuid)::uuid[]) AS liked " +
"FROM quotes q " +
"LEFT JOIN quotes_likes ql ON ql.quote_uuid = q.uuid " +
"WHERE display_at = :date " +
"GROUP BY q.quote, q.author, q.display_at;", nativeQuery = true)
Optional<QuoteOfTheDay> getQuoteOfTheDay(#Param("userUUID") UUID userUUID,#Param("date") LocalDate date);
Refer this for more details on how to use the #Query annotation.

Bad SQL grammar, Oracle : while the query is working fine in DB editor in Spring Boot Application

I am using Oracle DB with Spring Boot Application. The query is working fine in DBeaver but not in actual application. I have copied the query from the console error message.
Query calling function:
public List<UserFullNameDesignationDto> getUserFullNameDesignation(String[] userNames) {
String queryParam = "";
for (String uName : userNames) {
queryParam += "'" + uName + "',";
}
queryParam = queryParam.substring(0, queryParam.length() - 1);
String sql =
"SELECT\n"
+ "\tu.USERNAME,\n"
+ "\tu.FULL_NAME,\n"
+ "\tcd.NAME \n"
+ "FROM\n"
+ "\tUSER_ENTITY u\n"
+ "LEFT JOIN CORE_DESIGNATIONS cd ON u.DESIGNATION_ID = cd.ID \n"
+ "WHERE\n"
+ "\tu.USERNAME IN ("
+ queryParam
+ ");\n";
var rowMapper = BeanPropertyRowMapper.newInstance(UserFullNameDesignationDto.class);
List<UserFullNameDesignationDto> list = jdbcTemplate.query(sql, rowMapper);
System.out.println(list);
return jdbcTemplate.query(sql, rowMapper);
}
Stack trace:
org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [SELECT
u.USERNAME,
u.FULL_NAME,
cd.NAME
FROM
USER_ENTITY u
LEFT JOIN CORE_DESIGNATIONS cd ON u.DESIGNATION_ID = cd.ID
WHERE
u.USERNAME IN ('aro_user','afo_user1','afo_user1','afo_user1','afo_user1','afo_user1');
]; nested exception is java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended
............
Caused by: java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended
This line will be
'aro_user','afo_user1','afo_user1','afo_user1','afo_user1','afo_user1'
replaced by variable.
The root cause of the error is that you copied the semicolon in the JDBCTemplate statement (which works in SQL IDE but not in JDBC)
+ ");\n";
remove it
+ ")\n";
and it will work (or you get an other error;)
Anyway you should re-think your way of concatenation input in the SQL statement towards the usage of bind variables. There are lot of examples for binding IN list on this site.
As far as I can tell, you'll have to split values stored in that variable into rows. How? Like this:
SQL> with test(queryParam) as
2 (select q'['aro_user','afo_user1','afo_user1','afo_user1','afo_user1','afo_user1']' from dual)
3 select regexp_substr(queryParam, '[^,]+', 1, level) val
4 from test
5 connect by level <= regexp_count(queryParam, ',') + 1
6 /
VAL
----------------------------------------------------------------------
'aro_user'
'afo_user1'
'afo_user1'
'afo_user1'
'afo_user1'
'afo_user1'
6 rows selected.
SQL>
It means that this:
+ "\tu.USERNAME IN ("
+ queryParam
+ ");\n";
should be modified so that queryParam is replaced by
( SELECT REGEXP_SUBSTR (queryParam,
'[^,]+',
1,
LEVEL) val
FROM test
CONNECT BY LEVEL <= REGEXP_COUNT (queryParam, ',') + 1)
List<String> userIds = Arrays.asList("User1", "User2");
String inSql = String.join(",", Collections.nCopies(userIds.size(), "?"));
List<User> employees = jdbcTemplate.query(String.format("SELECT * FROM Users WHERE id IN (%s)", inSql), userIds.toArray());
Please see, https://www.baeldung.com/spring-jdbctemplate-in-list for

Spring JPA Query is not recognizing Spatial Types

I'm trying to make a native query request through spring JPA Query annotation using Spacial data types.
The query works perfectly when asked to execute through the console or even in the database.
But when he is asked to be used through Spring.
Does anyone know what I'm doing wrong? or there is a better way to achieve the same result (leaving all the calculations DB sided)?
Thank you in advance
This is the query I'm trying to execute. Again, it works through console but fails to execute through spring boot request
#Query(value = "SELECT TOP 1 * FROM Vehicles v " +
"JOIN Bikelots l ON l.BikeLotId = v.BikeLotId " +
"JOIN BikeTypes b ON b.BikeTypeId = l.BikeTypeId " +
"WHERE b.BikeTypeId = ?1 " +
"ORDER BY " +
"Geography::STGeomFromText(v.Point.MakeValid().STAsText(),4326) " +
".STDistance(Geography::STGeomFromText(Geometry::Point(?2,?3,4326).MakeValid().STAsText(),4326)) "
, nativeQuery = true)
com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near 'Geography:'.
Im using this dialect in application.properties
spring.jpa.database-platform=org.hibernate.spatial.dialect.sqlserver.SqlServer2008SpatialDialect
The given error was caused because jpa hibernate recognizes the character ":" as a placeholder for an upcoming variable.
By placing the query in a String variable, then adding "\\" before each ":" and assigning the string to the value of #Query, solved the problem. See code for example
String query = "SELECT TOP 1 * FROM Vehicles v " +
"JOIN Bikelots l ON l.BikeLotId = v.BikeLotId " +
"JOIN BikeTypes b ON b.BikeTypeId = l.BikeTypeId " +
"WHERE b.BikeTypeId = ?1 " +
"ORDER BY " +
"Geography\\:\\:STGeomFromText(v.Point.MakeValid().STAsText(),4326) " +
".STDistance(Geography\\:\\:STGeomFromText(Geometry\\:\\:Point(?2,?3,4326).MakeValid().STAsText(),4326)) ";
#Query(value = query, nativeQuery = true)

Named Query to SELECT rows with MAX(column name), DISTINCT by another column

I have a case similar to the one described in this question, I wrote an identical query which works, but when I try to write it as a jpql named query, I'm getting an error.
My query:
#NamedQuery(
name = "findRankingsBetween",
query = "SELECT rt FROM Rankingtable rt " +
"INNER JOIN " +
"(SELECT teamId, MAX(lastupdate) as MaxDateTime " +
"FROM Rankingtable " +
"GROUP BY teamId) grouped " +
"ON rt.teamId = grouped.teamId " +
"AND rt.lastupdate = grouped.MaxDateTime " +
"WHERE rt.lastupdate BETWEEN :from AND :to"
)
Error:
Error in named query: findRankingsBetween: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: ( near line 1, column 79
How to write the query properly in jpql?
As noted in this answer, a subquery in JPQL can only occur in select and where clauses.
Hibernate doc.
An equivalent query in JPQL is:
"SELECT rt FROM Rankingtable rt " +
"WHERE rt.lastupdate = (SELECT MAX(r2.lastupdate) " +
"FROM Rankingtable r2 " +
"WHERE r2.teamid = rt.teamid) " +
"AND rt.lastupdate BETWEEN :from AND :to"

Java Regex capture any (.*) with DOTALL ignores zero-width positive lookahead

Not a regex expert, but I know enough to be dangerous, need some help with an expression I am working on. Long story short, a recent database upgrade has invalidated thousands of queries within string literals of a legacy application that I support. I am writing a few expressions to capture the majority of these and hopefully fix them programatically.
Consider the following:
Query query = session
.createSQLQuery("SELECT distinct p.userid, p.name, f.hsid, "
+ "p.vid, p.vname, p.paymentdate, p.amount "
+ "FROM vk.payment p, (select * from vs.fuser) fu, (select * from vs.fac) f "
+ "WHERE p.description = 'Check' AND "
+ "p.paymentdate >= :startDate and p.paymentdate <= :endDate AND "
+ "fu.userid = p.userid AND fu.facid = f.facid "
+ "ORDER BY p.userid");
query.setParameter("startDate", startDate);
query.setParameter("endDate", endDate);
I have the following DOTALL expression to attempt and capture simply the ugly contents of the method argument.
(?s)(?<=\.createSQLQuery\(")(.*)(?="\)\;)
I specify the DOTALL flag with (?s) a non-capturing look behind to get \.createSQLQuery\(", capture everything including line breaks with (.*), and finally a non capturing positive lookahead to stop the capture at "\)\;.
I am expecting to capture the following:
SELECT distinct p.userid, p.name, f.hsid, "
+ "p.vid, p.vname, p.paymentdate, p.amount "
+ "FROM vk.payment p, (select * from vs.fuser) fu, (select * from vs.fac) f "
+ "WHERE p.description = 'Check' AND "
+ "p.paymentdate >= :startDate and p.paymentdate <= :endDate AND "
+ "fu.userid = p.userid AND fu.facid = f.facid "
+ "ORDER BY p.userid
Instead the expression is a lot greedier than I anticipated and is capturing this:
SELECT distinct p.userid, p.name, f.hsid, "
+ "p.vid, p.vname, p.paymentdate, p.amount "
+ "FROM vk.payment p, (select * from vs.fuser) fu, (select * from vs.fac) f "
+ "WHERE p.description = 'Check' AND "
+ "p.paymentdate >= :startDate and p.paymentdate <= :endDate AND "
+ "fu.userid = p.userid AND fu.facid = f.facid "
+ "ORDER BY p.userid");
query.setParameter("startDate", startDate);
query.setParameter("endDate", endDate);
... to EOF
The thing is that without the DOTALL the expression works as expected on a single line:
Query query = session.createSQLQuery("SELECT .... ");
and captures without the remaining characters on the end...
SELECT ....
Is there some aspect of DOTALL that every regex guru seems to know that does not seem to be documented anywhere? Does DOTALL not work with positive lookahead?
I appreciate any help!
Make the * quantifier non-greedy by adding a ? after it, like so: .*?
Also why are you even using lookarounds? It can lead to undesired behavior in some cases to use them without thought like this. (And it always irritates me. (-; )
You could just use:
(?s)\.createSQLQuery\("(.*?)"\);

Categories