The Query on executing in PostgreSQL Database is fetching the records properly. But, when implemented using createnativeQuery, I am getting Error
ERROR SqlExceptionHelper:131 - ERROR: syntax error at or near ":"
Query Executed successfully in Postgres Database is mentioned below
select d.dt::date as date_current,
coalesce(underwriter_daily_cap, daily_file_cap) as file_cap,
user_id
from generate_series(date '2019-04-05', date '2019-04-09', interval '1'
day) as d(dt)
left join (
select upd.*, ud.daily_file_cap
from mod_underwriter_daily_file_count upd
join lsa_assignment_details ud on ud.user_id = upd.user_id
where ud.user_id = 350
) upd on upd.date_current = d.dt::date
ORDER BY d.dt DESC;
DAO Layer code is as follows
#SuppressWarnings("unchecked")
public List<Object[]> getUnderWriterCap(String dynamicUserId) {
log.info("Entered UserSkillMappingHibDAO :
getUnderWriterCap");
Session session = sessionFactory.getCurrentSession();
Date currentDateMinusFive =
DateUtil.getLastFiveDayOldPSTDate();
Date currentDate = DateUtil.getCurrentPSTDate();
String queryString = " select d.dt::date as date_current,
coalesce(underwriter_daily_cap, daily_file_cap) as file_cap, user_id "
+" from generate_series ( date '"+DateUtil.getDateFormat(currentDateMinusFive)+"', date '"+DateUtil.getDateFormat(currentDate)+"', INTERVAL '1' DAY ) as d(dt) "
+" left join ( select upd.*, ud.daily_file_cap from mod_underwriter_daily_file_count upd "
+" join lsa_assignment_details ud on ud.user_id = upd.user_id where ud.user_id = "+ dynamicUserId
+") upd on upd.date_current = d.dt::date ORDER BY d.dt DESC " ;
List<Object[]> records = session.createNativeQuery(queryString)
.getResultList();
return records;
}
The Exception got in console while executing the above code is as below
Hibernate: select d.dt:date as date_current, coalesce(underwriter_daily_cap, daily_file_cap) as file_cap, user_id from generate_series ( date '2019-04-04', date '2019-04-09', INTERVAL '1' DAY ) as d(dt) left join ( select upd.*, ud.daily_file_cap from mod_underwriter_daily_file_count upd join lsa_assignment_details ud on ud.user_id = upd.user_id where ud.user_id = 403) upd on upd.date_current = d.dt:date ORDER BY d.dt DESC
2019-04-09 18:58 ERROR SqlExceptionHelper:131 - ERROR: syntax error at or near ":"
Position: 14
There are several errors in this. More important than the syntax error is how you're appending a parameter as a string literal.
Instead of:
session.createNativeQuery("select * from tbl where param = '" + value + "'");
You have to use prepared statements (that is the term to look-up). This is extremely important for security.
Query q = session.createNativeQuery("select * from tbl where param = :par1");
q.setParameter("par1", value);
Now as for the syntax error, it's caused by your use of PostgreSQL's custom typecast syntax. You have to replace it with the standard SQL typecast from d.dt::date to cast(d.dt as date), because Hibernate expects : to be the start of a named parameter.
String queryString = "select cast(d.dt as date) as date_current, "
+" coalesce(underwriter_daily_cap, daily_file_cap) as file_cap, user_id "
+" from generate_series ( current_date - 5, current_date, INTERVAL '1' DAY ) as d(dt) "
+" left join ( select upd.*, ud.daily_file_cap from mod_underwriter_daily_file_count upd "
+" join lsa_assignment_details ud on ud.user_id = upd.user_id where ud.user_id = :dynuid ) upd on upd.date_current = cast(d.dt as date) ORDER BY d.dt DESC " ;
List<Object[]> records = session.createNativeQuery(queryString)
.setParameter("dynuid", dynamicUserId)
.getResultList();
I also replaced you current date java calculations with database functions. Instead of doing:
Date currentDateMinusFive = DateUtil.getLastFiveDayOldPSTDate();
Date currentDate = DateUtil.getCurrentPSTDate();
...
.setParameter("ds", DateUtil.getDateFormat(currentDateMinusFive))
.setParameter("de", DateUtil.getDateFormat(currentDate))
You have the database do it for you using current_date - 5 and current_date.
Another thing you should watch-out for, since your DateUtil is using the old java.util.Date class and related stuff is that if you are using a SimpleDateFormatter to format it, then it must be a new instance on every call. Do not optimize it to a static final, because it's not thread-safe. I've suffered from this.
edit: I also believe your query can be optimized much further into this, and it will have the same results:
select upd.date_current, underwriter_daily_cap, daily_file_cap from mod_underwriter_daily_file_count upd
join lsa_assignment_details ud on ud.user_id = upd.user_id
where ud.user_id = :dynuid and
upd.date_current between current_date - 5 and current_date
ORDER BY d.dt DESC
Notice I removed some fields from the select, like user_id, because you are already telling the database which one you want. The one major difference is this query will skip results for days with no entries.
Related
I'm using Spring Data JPA. Could someone say, how to fix this error: "java.sql.SQLSyntaxErrorException: Unknown column 's' in 'field list'" while executing this simple request. "s" is alias for session table. I shortened the query.
#Query(value =
"SELECT l.name as lName, c.id as clientId, c.name as clientName, s.id as sessionId, a.ss_id as ssId, " +
"u.first_name as firstName, u.last_name as lastName, s.start_date as startDate, s.end_date as endDate, " +
"sc.version as version " +
"FROM session as s " +
"join scenario sc on sc.id = s.scenario_id " +
.........
"left join client c on c.id = p.client_id " +
"WHERE s.status = 'COMPLETED' " +
"and (s.record_rejected IS NULL OR s.record_rejected = 0) " +
"and sfe.id IS NULL " +
.........
"and s.end_date between :startDate and :endDate",
nativeQuery = true)
Page<DataItem> findData(Pageable pageable, #Param("startDate") LocalDateTime startDate, #Param("endDate") LocalDateTime endDate, .......);
}
In log I see the reason of the problem, after my main request spring data executes count request for Pageable object and this request starts with: select count(s) FROM session as s, but this is wrong. You can see it below in the text:
Hibernate: SELECT l.name as lName....
Hibernate: select count(s) FROM session as s ....
2022-02-24 22:10:51.864 WARN [app,363fdd7d5edaa51c,175b13cac216908e,true] 1 --- [nio-8082-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1054, SQLState: 42S22
2022-02-24 22:10:51.864 ERROR [app,363fdd7d5edaa51c,175b13cac216908e,true] 1 --- [nio-8082-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : Unknown column 's' in 'field list'
on the second line framework tries execute select count(s), but s is an alias for the table session. And this happens only when required size is less than totalElements, if not, then request is success.
DataItem is an interface projection.
What's wrong? Why framework tries to use table alias inside count() function?
I've tried to use countQuery argument in #Query annotation, but it didn't help.
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
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
I have problem with sorting.
Repository method:
#Query(nativeQuery = true,
value = "SELECT D.ID as dealerId , D.NAME as dealerName, K.ID as kpiId, " +
"K.NAME as kpiName FROM REGION R, DEALER D, KPI K "
+ "WHERE R.IMPORTER_ID = :importerId "
+ "AND D.REGION_ID = R.ID "
+ "AND K.IMPORTER_ID = :importerId ")
Page<DealersKpiTargets> getDealersKpiTargets(#Param("importerId") Long importerId, Pageable pageable);
Pageable object:
Page request [number: 0, size 20, sort: name: DESC]
Hibernate log:
Hibernate: SELECT D.ID as dealerId , D.NAME as dealerName, K.ID as kpiId, K.NAME as kpiName FROM REGION R, DEALER D, KPI K WHERE R.IMPORTER_ID = ? AND D.REGION_ID = R.ID AND K.IMPORTER_ID = ? order by R.name desc limit ?
I don't understand where R.name prefix came from, in the order by part in Hibernate (towards the end).
For reference, I am using:
spring-data-jpa version 2.0.7.RELEASE
spring-boot-starter-data-jpa version 2.0.2.RELEASE
UPDATE
I have solved this by changing the query from the native query to jpa query and it's working. And I changed cartesian to join version.
#Query("SELECT dealerEntity.id AS dealerId , dealerEntity.name AS dealerName, kpiEntity.id AS kpiId, " +
"kpiEntity.name AS kpiName FROM KpiEntity kpiEntity "
+ "JOIN RegionEntity regionEntity ON regionEntity.importerEntity = kpiEntity.importerEntity "
+ "JOIN DealerEntity dealerEntity ON dealerEntity.importerEntity = regionEntity.importerEntity "
+ "WHERE kpiEntity.importerEntity = :importerEntity ")
Page<DealersKpiTargets> getDealersKpiTargets(#Param("importerEntity") ImporterEntity importerEntity, Pageable pageable);
here is jira ticket with more details which can be key for resolution (https://jira.spring.io/browse/DATAJPA-1613).
QueryUtils.ALIAS_MATCH
(?<=from)(?:\s)+([._[\P\\{Z}&&\P\\{Cc}&&\P\\{Cf}&&\P\\{P}]]+)(?:\sas)*(?:\s)+(?!(?:where|group\s*by|order\s*by))(\w+)
responsible to incorrect alias extraction. The solution for my case was rewrite native query, so it doesn't match the provided regexp.
This may be a little late to answer this question. But thought to share how I got around this issue.
For native queries, it seems like hibernate tries to use the alias of the first table used in the query when it applies the sorting criteria. In your case, the first table alias is R hence you see R.name desc in the query generated by hibernate.
One way to get around this issue is to wrap your query in a select clause and name it as R, like
"SELECT * FROM(SELECT D.ID as dealerId , D.NAME as dealerName, K.ID as kpiId, " +
"K.NAME as kpiName FROM REGION R, DEALER D, KPI K "
+ "WHERE R.IMPORTER_ID = :importerId "
+ "AND D.REGION_ID = R.ID "
+ "AND K.IMPORTER_ID = :importerId ) R"
This way at runtime hibernate would apply the sort criteria on top of your query which corresponds to R now.
It has Sort class for this you can use this maybe. Besides, it is easy to use.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.sorting
I faced similar issue especially in case of complex queries where there is ORDER BY with in the query. I was getting syntax error because a , was getting added before ORDER BY.
The way I solved this issue was to create a VIEW with the SELECT query having necessary fields required for result set and WHERE condition (so you can run query with params in WHERE condition against the VIEW). And write native query to SELECT FROM the VIEW
CREATE VIEW my_view AS (// your complex select query with required fields);
#Query("SELECT field1 AS alias1, field2 AS alias2 FROM my_view "
+ "WHERE field3 = :param1 AND field4 = :param2")
Page<MyDto> myFunction(#Param("param1") Long param1, #Param("param1") String param2, Pageable pageable);
I would like to perform a query in HQL similar to this in SQL:
SELECT (
SELECT COUNT(*) FROM EMPLOYER +
SELECT COUNT(*) FROM COMPANIES
)
FROM DUAL
When I add "FROM DUAL" to the query I get an error:
org.hibernate.hql.ast.QuerySyntaxException: DUAL is not mapped
And if I leave off the "FROM DUAL" I get:
org.hibernate.hql.ast.QuerySyntaxException: unexpected end of subtree
Any recommendations?
In SQL, subqueries need their own set of parentheses, so try this:
SELECT ((SELECT COUNT(*) FROM EMPLOYER) +
(SELECT COUNT(*) FROM COMPANIES)
)
If that doesn't work, resort to a from clause:
SELECT e.cnt + c.cnt
FROM (SELECT COUNT(*) as cnt FROM EMPLOYER
) e CROSS JOIN +
(SELECT COUNT(*) as cnt
FROM COMPANIES
) c
Since you didn't join the Company and Employee tables you'd better run two queries:
int companyCount = ((Number) getSession().createQuery("select count(*) from Company").uniqueResult()).intValue();
int employeeCount = ((Number) getSession().createQuery("select count(*) from Employee").uniqueResult()).intValue();
int totalCount = companyCount + employeeCount;
The (Number) is needed since PostgreSQL returns a BigInteger while HDSQLDB returns an Integer, but both are subclasses of Number.