Use postgres function timestamp in JpaRepository - java

I try to group by date only, column active_to is timestamp so it has time also. This query works in pgAdmin but JpaRepository seems to have problem even if it is native query. How can I modify this query to work using JpaRepository?
#Query(value = "SELECT o.active_to::timestamp::date, count(o) as sum from work_order o group by o.active_to::timestamp::date order by o.active_to::timestamp::date asc limit 7", nativeQuery = true)
I get this error:
org.postgresql.util.PSQLException: ERROR: syntax error at or near ":"
Position: 19

You cannot use : because this is the character that starts a named parameter.
You have to use cast.
#Query(value = "SELECT cast(cast(o.active_to as timestamp) as date), count(o) as sum " +
"from work_order o group by cast(cast(o.active_to as timestamp) as date) " +
"order by cast(cast(o.active_to as timestamp) as date) asc limit 7",
nativeQuery = true)
Cast and :: are similar. Read more about here:
https://www.postgresql.org/docs/current/sql-expressions.html#SQL-SYNTAX-TYPE-CASTS

Related

JPA Repository nativeQuery with pageable, join table not working when pageable.size = 1

I have this sql query that works fine
SELECT ppd.userId, AVG(Coalesce(sm.score, 0)) AS avgScore
FROM Table1 ppd
LEFT JOIN Table2 sm ON ppd.userId = sm.userId AND sm.created BETWEEN start AND end
WHERE ppd.someId IN (listOfIds)
GROUP BY ppd.userId ORDER BY avgScore DESC LIMIT 1 OFFSET 0;
I have written a query for a method in a JPARepository that looks like the following
#Query(value = "SELECT ppd.userId, AVG(Coalesce(sm.score, 0)) AS avgScore " +
" FROM Table1 ppd " +
" LEFT JOIN Table2 sm ON sm.userId = ppd.userId AND sm.created BETWEEN :start AND :end " +
" WHERE ppd.someId IN (:IdList) GROUP BY ppd.userId",
nativeQuery = true)
Page<MyDtoProjection> getAvg(#Param("IdList") List<String> IdList,
#Param("start") Long start,
#Param("end") Long end,
Pageable pageable);
Which works just as expected except when the pageable size is 1 (SQL query with Limit 1 works fine).
For the pageable parameter the service sends the following pageable object
Sort sort = JpaSort.unsafe(Sort.Direction.ASC, "(avgScore)");
Pageable pageable = PageRequest.of(offset, limit, sort);
The request sets offset=0 and limit=1
The error I'm receiving from request using repository code is this one:
Unknown column 'ppd' in 'field list'\nQuery is: select count(ppd)..., I don't know why it is taking the alias ppd as a column name, also, I read from another post that this way of executing native queries performs a count (which can be seen in the error message, I did not specify that count query), and that it can be specified by setting countQuery parameter, but I'm not sure what to write there.
Solve it>
Just added the countQuery to the #Query annotation, I was not so sure what to place there, but it was simple
#Query(value = "SELECT ppd.userId, AVG(Coalesce(sm.score, 0)) AS avgScore " +
" FROM Table1 ppd " +
" LEFT JOIN Table2 sm ON sm.userId = ppd.userId AND sm.created BETWEEN :start AND :end " +
" WHERE ppd.someId IN (:IdList) GROUP BY ppd.userId",
countQuery = "SELECT COUNT(ppd.userId) FROM Table1 ppd " +
"WHERE ppd.userId IN (:IdList) GROUP BY ppd.userId",
nativeQuery = true)
Page<MyDtoProjection> getAvg(#Param("IdList") List<String> IdList,
#Param("start") Long start,
#Param("end") Long end,
Pageable pageable);
This is the only post I found that mentions the countQuery and how it works in one of the answers, go check it out if someone is going through the same
Spring Data and Native Query with pagination

JPA Repository : Cannot bind parameter for timezone

I have the following code in JPA repository and it works.
#Query(
value =
"SELECT EXTRACT(HOUR FROM STO.createddate\\:\\:timestamptz at time zone 'Asia/Seoul') AS hour,\n"
+ " COUNT(STO.id) AS count, SUM(STO.grandtotalprice) AS sum, AVG(STO.grandtotalprice) AS average\n"
+ "FROM store.storeorder AS STO\n"
+ "WHERE STO.store_id=?1 AND STO.createddate >= ?2 AND STO.createddate < ?3 AND STO.orderstatus IN ('CLOSED')\n"
+ "GROUP BY EXTRACT(HOUR FROM STO.createddate\\:\\:timestamptz at time zone 'Asia/Seoul') \n"
+ "ORDER BY hour ASC;",
nativeQuery = true)
List<ReportHourly> hourlyReport(
UUID storeId, LocalDateTime from, LocalDateTime to);
However, when I try to input timezone as parameter like below, it fails with saying
org.postgresql.util.PSQLException: ERROR: column "createddate" must appear in the GROUP BY clause or be used in an aggregate function
#Query(
value =
"SELECT EXTRACT(HOUR FROM STO.createddate\\:\\:timestamptz at time zone ?4) AS hour,\n"
+ " COUNT(STO.id) AS count, SUM(STO.grandtotalprice) AS sum, AVG(STO.grandtotalprice) AS average\n"
+ "FROM store.storeorder AS STO\n"
+ "WHERE STO.store_id=?1 AND STO.createddate >= ?2 AND STO.createddate < ?3 AND STO.orderstatus IN ('CLOSED')\n"
+ "GROUP BY EXTRACT(HOUR FROM STO.createddate\\:\\:timestamptz at time zone ?4) \n"
+ "ORDER BY hour ASC;",
nativeQuery = true)
List<ReportHourly> hourlyReport(
UUID storeId, LocalDateTime from, LocalDateTime to, String timeZone);
I am not sure why parameterization doesn't work for this case.
I think the problem here is that JDBC doesn't really know about indexed bind arguments, it only knows about ? for binding.
This means the two occurrences fo ?4 get translated into two different bind parameters and therefore Postgres sees an expression in the select clause that is not part of the GROUP BY nor an aggregate function.
Since by construction the two actually are the same you should be fine wrapping the expression for hour in MAX(...) or any other aggregate function that returns the argument value when applied to a single row.

Check if an integer is in a jsonb list

I'm trying to write a native query in JPA. I want to verify if an element exists in a jsonb column. However, I'm getting the error integer <# jsonb.
This is my query:
#Query(
value = "SELECT u FROM user u WHERE (u.depNum = ?1 and superAdmin = true " +
" and ?2 <# (u.listUsers)) ",
nativeQuery = true
)
public List<EbUser> selectSuperAdmin(Integer depNum, Integer userNum);
The error happens here: ?2 <# (u.listUsers). How can I verify that listUsers contains the userNum or how can I convert the userNum to jsonb in Java?
You can do the conversion in PostgreSQL.
and to_jsonb(ARRAY[?2]) <# (u.listUsers))
as long as JPA doesn't interfere with passing this construct into PostgreSQL, I have not tested that part.

I got a syntax error when trying to call JPA function

When Im trying to call JPA function this statement I got an error: syntax error at or near ":"
public interface BcaTestRepository extends CrudRepository<InBodyBCA, Long> {
#Query(value = "SELECT * FROM in_body_bca bca WHERE person_id = :personId " +
"AND to_timestamp(bca.datetimes::text, 'YYYYMMDDHH24MISS') BETWEEN :startRange AND :endRange",
nativeQuery = true)
List<InBodyBCA> findAllByPersonId(#Param("personId") Long personId,
#Param("startRange") LocalDateTime startRange,
#Param("endRange") LocalDateTime endRange);
But in PgAdmin the query works fine
SELECT id, to_timestamp(datetimes::text, 'YYYYMMDDHH24MISS') as dt FROM in_body_bca WHERE to_date(datetimes::text, 'YYYYMMDDHH24MISS')
BETWEEN '2018-05-07' AND '2019-05-07' ORDER BY to_date(datetimes::text, 'YYYYMMDDHH24MISS') DESC ;
You use the double colon here: bca.datetimes::text. JPA would look for text variable name.
You need to escape it:
bca.datetimes\\:\\:text

Spring Boot: JPA QueryDSL: How to Make a Named Delete?

In the QueryDSL repository, I can make a named query in this way:
public interface HistoricalDataRepository
extends PagingAndSortingRepository<HistoricalData, Long>,
QueryDslPredicateExecutor<HistoricalData> {
List<HistoricalData> findAll(Predicate predicate);
HistoricalData findByKeyAndDate(String key, String date);
#Query(value = "SELECT * FROM historical_data h WHERE "
+ " h.key = :key "
+ " AND h.date <= :date "
+ " order by date desc"
+ " limit 1"
, nativeQuery = true)
HistoricalData myFindByKeyLowerOrEqualToDate(
#Param("key") String key
, #Param("date") Date date
);
How can I perform a
DELETE FROM HISTORICAL_DATA;
If I use the same syntax as above (with the #Queryannotation), I get an exception:
org.springframework.orm.jpa.JpaSystemException:
could not extract ResultSet; nested exception is
org.hibernate.exception.GenericJDBCException: could not extract ResultSet
Background: I do not want to use a
historicalDataRepository.deleteAll();
as this has a VERY low performance.
EDIT:
My syntax would look like the following:
#Query(value = "DELETE FROM HISTORICAL_DATA", nativeQuery = true)
void myDeleteAll();
Looks like, you are combining both JPA query as well as native query. For the syntax you have given, you have to specify it as native as shown below
#Query(value = "DELETE FROM HISTORICAL_DATA", nativeQuery = true)

Categories