Spring Data native query with params don't work - java

I have a native query like the following one:
#Query(value = "SELECT * FROM (" +
" SELECT result.*, ROWNUM rn FROM (" +
" SELECT tmp.* FROM (" +
" SELECT " +
" e.id, " +
" e.employee_number, " +
" d.name, " +
" d.surname " +
" FROM employee e INNER JOIN detail d ON e.id_detail = d.id " +
" WHERE e.status = :status " +
" ) tmp " +
" ORDER BY :sortColumn :sortDirection " +
" ) result " +
" WHERE ROWNUM <= (:pageIndex + :pageSize) " +
") " +
"WHERE rn > :pageIndex "
, nativeQuery = true)
ArrayList<Object> getEmployeeDetails( #Param("status") EmployeeStatus status,
#Param("pageSize") int pageSize,
#Param("pageIndex") int pageIndex,
#Param("sortDirection") String sortDirection,
#Param("sortColumn") String sortColumn);
and I'm getting the following errors:
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
// ...
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
// ...
Caused by: java.sql.SQLSyntaxErrorException: ORA-01745: invalid host/bind variable name
What I tried is different return type (and didn't manage to find out which one to use eventually), inserting params with #Param() annotations.
The query itself does work - I tried it directly in the database, but I'm experiencing problems with handling it in Spring.
The query itself for easy debugging:
SELECT * FROM (
SELECT result.*, ROWNUM rn FROM (
SELECT tmp.* FROM (
SELECT
e.id,
e.employee_number,
d.name,
d.surname
FROM employee e INNER JOIN detail d ON e.id_detail = d.id
WHERE e.status = 'status'
) tmp
ORDER BY tmp.name desc
) result
WHERE ROWNUM <= (0 + 5)
)
WHERE rn > 0
EDIT:
I've updated the question with comment suggestions of removing all of the \n's and checking for missing whitespaces.
Plain query, without using any parameters also work, but as I start to insert parameters through #Param() annotations or binds (?1) it stops working giving the errors I updated above.

if EmployeeStatus is enum you have to use this in your query
WHERE e.status = :#{#status.name()}

Related

Using parameters in JPQL query with aggregate functions

I use JPQL queries in my SpringBoot project. I have a query with COUNT function. The query is:
#Query(value =
"SELECT new ua.edu.chdtu.deanoffice.service.course.selective.statistics.StudentsRegistrationOnCoursesPercent(" +
"2021 - scsd.studentDegree.studentGroup.creationYear + scsd.studentDegree.studentGroup.realBeginYear, " +
"COUNT(DISTINCT scsd.studentDegree.id)) " +
"FROM SelectiveCoursesStudentDegrees AS scsd " +
"GROUP BY scsd.selectiveCourse.studyYear, scsd.studentDegree.specialization.degree.id, " +
"scsd.studentDegree.active, " +
"2021 - scsd.studentDegree.studentGroup.creationYear + scsd.studentDegree.studentGroup.realBeginYear " +
"having scsd.selectiveCourse.studyYear = :studyYear AND " +
"scsd.studentDegree.specialization.degree.id = :degreeId AND " +
"scsd.studentDegree.active = true")
List<StudentsRegistrationOnCoursesPercent> findPercentStudentsWhoChosenSelectiveCourse(#Param("studyYear") int studyYear,
#Param("degreeId") int degreeId);
And it works fine.
But when I change a literal 2021 to a JPQL query parameter :currYear (only substitute literal with parameter, nothing else), I get an error:
2022-04-13 15:10:17 [XNIO-2 task-1] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ERROR: column "studentgro2_.creation_year" must appear in the GROUP BY clause or be used in an aggregate function
Position: 11
2022-04-13 15:10:17 [XNIO-2 task-1] ERROR u.e.c.d.a.g.ExceptionHandlerAdvice - ERROR
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:261)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:503)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:209)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
How can I fix it?
The changed query is the following:
#Query(value =
"SELECT new ua.edu.chdtu.deanoffice.service.course.selective.statistics.StudentsRegistrationOnCoursesPercent(" +
":currYear - scsd.studentDegree.studentGroup.creationYear + scsd.studentDegree.studentGroup.realBeginYear, " +
"COUNT(DISTINCT scsd.studentDegree.id)) " +
"FROM SelectiveCoursesStudentDegrees AS scsd " +
"GROUP BY scsd.selectiveCourse.studyYear, scsd.studentDegree.specialization.degree.id, " +
"scsd.studentDegree.active, " +
":currYear - scsd.studentDegree.studentGroup.creationYear + scsd.studentDegree.studentGroup.realBeginYear " +
"having scsd.selectiveCourse.studyYear = :studyYear AND " +
"scsd.studentDegree.specialization.degree.id = :degreeId AND " +
"scsd.studentDegree.active = true")
List<StudentsRegistrationOnCoursesPercent> findPercentStudentsWhoChosenSelectiveCourse(#Param("studyYear") int studyYear,
#Param("degreeId") int degreeId,
#Param("currYear") int currYear);
probably there is some problem with parameter substitution and
:currYear - scsd.studentDegree.studentGroup.creationYear + scsd.studentDegree.studentGroup.realBeginYear
is not recognized as th same "column" in select and group by parts
you could try using group by 1 as in What does SQL clause "GROUP BY 1" mean?

How to rewrite postgresSql query as Spring-data jpa query

I am stuck at the moment while trying to write the next query as a spring-data JPA query:
with recursive s as (
select *
from t
where file_id = '12345'
union all
select dfs.*
from t dfs
join s on s.file_id = dfs.parent_folder_id
)
select * from s;
I have tried the next:
#Query(value = "with recursive subfiles as (
select * from t where file_id=?1
union all
dfs.* from t dfs join subfiles s
on s.file_id = dfs.parent_folder_id)
select file_id from subfiles", nativeQuery = true)
But I get the next error:
Method threw 'org.springframework.dao.InvalidDataAccessResourceUsageException' exception.
could not extract ResultSet; SQL [n/a]
org.hibernate.exception.SQLGrammarException: could not extract ResultSet
org.postgresql.util.PSQLException: ERROR: syntax error at or near "dfs"
The query should list all direct or indirect dependent children for a specific id. (a similar post here)
I have managed to fix it using the next format:
#Query(nativeQuery = true,
value = "with recursive subfiles as " +
"(select * " +
"from t " +
"where file_id=?1 " +
"union all " +
"select dfs.* " +
"from t dfs " +
"join subfiles s " +
"on s.file_id = dfs.parent_folder_id) " +
"select file_id from subfiles")
List<String> listAllByParentId(String folderId);

org.postgresql.util.PSQLException: ERROR: syntax error at or near ":"

I am running an SQL query from PgAdmin4 which runs successfully, but when i take that same query to run it from my Spring Boot application i have an error " org.postgresql.util.PSQLException: ERROR: syntax error at or near ":" "
Here is what the SQL query looks like:
SELECT
student.surname, student.first_name, student.last_name,
jsonb_pretty(elems)
FROM assessment, jsonb_array_elements(assessment.assessment) AS elems
JOIN student ON student.id = (elems->>'student_id')::uuid
WHERE subject_id = 2
AND academy_year_id =3
AND form_id = 2
AND term_id = 1
AND section_id = 4;
And this run successfully from PgAdmin4.
This is my implementation in my Repository
#Query(nativeQuery = true, value = "SELECT\n" +
" student.surname, student.first_name, student.last_name,\n" +
" jsonb_pretty(elems)\n" +
"FROM assessment, jsonb_array_elements(assessment.assessment) AS elems\n" +
"JOIN student ON student.id = (elems->>'student_id')::uuid\n" +
"WHERE subject_id = 2\n" +
"AND academy_year_id =3\n" +
"AND form_id = 2\n" +
" AND term_id = 1\n" +
"AND section_id = 4;")
Object[] getSubjectAssessments();
And when my API calls this method i get this error message
org.postgresql.util.PSQLException: ERROR: syntax error at or near ":"
I don't know what I am doing wrong.
JPA can't handle the Postgres specific cast operator ::.
Use cast() instead:
JOIN student ON student.id = cast(elems->>'student_id' as uuid)

Bad SQL grammar -The column name was not found in this ResultSet?

Hello I am using a JDBC query and I am having this error but I don't understand why, or what exactly is the meaning of this error and what is wrong with the query.
The query is as below
private List<StatisticsLog> runStatistics(Integer partnerId, LocalDate ldStart, LocalDateTime ldtEnd, String statType)
{
return jdbcTemplate.query("SELECT S.APP_ID, S.LOG_TYPE, ACC.CONTACT_PERSON_FIRST_NAME, ACC.CONTACT_PERSON_LAST_NAME, ACV.VERSION_APP_NAME, "
+ "'" + statType.trim() + "' STATTYPE, "
+ "ACV.APP_CATALOG_ID, ACV.APP_CATALOG_VERSION_ID, ACV.VERSION, ACV.UPDATED_AT, ACV.VERSION_LOGO_EXT, ACV.HAS_LOGO, "
+ "LANG.LANGUAGE_NAME_SHORT, LANG.LANGUAGE_ID , S.count, S.PARTNER_ID, APP.CREATED_AT "
+ "FROM (SELECT partner_id, log_type, app_id, language_id, count(*) as count FROM public.statistics_log "
+ " WHERE partner_id = ? "
+ " and logged_at between ? and ? "
+ "group by 1, log_type, app_id, language_id) as S "
+ "INNER JOIN APP_CATALOG_ACCOUNT ACP ON ACP.APP_CATALOG_SERIAL_ID = S.APP_ID "
+ "INNER JOIN APP_CATALOG APP ON APP.APP_CATALOG_SERIAL_ID = S.APP_ID "
+ "INNER JOIN ACCOUNT ACC ON ACC.ACCOUNT_ID = S.PARTNER_ID "
+ "INNER JOIN APP_CATALOG_VERSION ACV on ACV.APP_CATALOG_SERIAL_ID = APP.APP_CATALOG_SERIAL_ID AND ACV.STATUS = 3 "
+ "INNER JOIN LANGUAGE LANG ON LANG.LANGUAGE_ID = ACV.LANGUAGE_ID "
+ "ORDER BY S.count desc ",
new Object[] { partnerId, ldStart, ldtEnd }, new StatisticsLogRowMapper());
}
and I am getting the error from this column CREATED_AT that is part of the app catalog, and I think it should be there, also for more detailed also I will attach StatisticsLogRowMapper
public class StatisticsLogRowMapper implements RowMapper<StatisticsLog>
{
#Override
public StatisticsLog mapRow(ResultSet rs, int rowNum) throws SQLException
{
StatisticsLog stat = new StatisticsLog();
stat.setAppId(rs.getInt("APP_ID"));
stat.setPartnerId(rs.getInt("PARTNER_ID"));
stat.setCount(rs.getLong("COUNT"));
stat.setCreatedAt(rs.getTimestamp("CREATED_AT").toLocalDateTime());
stat.setPartnerFirstName(rs.getString("CONTACT_PERSON_FIRST_NAME"));
stat.setPartnerLastName(rs.getString("CONTACT_PERSON_LAST_NAME"));
stat.setAppNameDefault(rs.getString("VERSION_APP_NAME"));
stat.setAppCatalogId(rs.getInt("APP_CATALOG_ID"));
stat.setStatType(rs.getString("STATTYPE"));
stat.setLogType(LogTypeEnum.valueOf(rs.getString("LOG_TYPE").trim()));
stat.setAppCatalogVersionId(rs.getInt("APP_CATALOG_VERSION_ID"));
stat.setVersion(rs.getInt("VERSION"));
stat.setUpdatedAt(rs.getDate("UPDATED_AT"));
stat.setVersionLogoExt(rs.getString("VERSION_LOGO_EXT"));
stat.setHasLogo(rs.getBoolean("HAS_LOGO"));
stat.setLanguageNameShort(rs.getString("LANGUAGE_NAME_SHORT"));
stat.setLanguageId(rs.getInt("LANGUAGE_ID"));
return stat;
}
}
THE ERROR IS: "PreparedStatementCallback; bad SQL grammar [SELECT S.APP_ID, S.LOG_TYPE, ACC.CONTACT_PERSON_FIRST_NAME, ACC.CONTACT_PERSON_LAST_NAME, ACV.VERSION_APP_NAME, 'days30' STATTYPE, ACV.APP_CATALOG_ID, ACV.APP_CATALOG_VERSION_ID, ACV.VERSION, ACV.UPDATED_AT, ACV.VERSION_LOGO_EXT, ACV.HAS_LOGO, LANG.LANGUAGE_NAME_SHORT, S.count, S.PARTNER_ID FROM (SELECT partner_id, log_type, app_id, language_id, count(*) as count FROM public.statistics_log WHERE logged_at between ? and ? group by 1, log_type, app_id, language_id, partner_id) as S INNER JOIN APP_CATALOG_ACCOUNT ACP ON ACP.APP_CATALOG_SERIAL_ID = S.APP_ID INNER JOIN APP_CATALOG APP ON APP.APP_CATALOG_SERIAL_ID = S.APP_ID INNER JOIN ACCOUNT ACC ON ACC.ACCOUNT_ID = S.PARTNER_ID INNER JOIN APP_CATALOG_VERSION ACV on ACV.APP_CATALOG_SERIAL_ID = APP.APP_CATALOG_SERIAL_ID AND ACV.STATUS = 3 INNER JOIN LANGUAGE LANG ON LANG.LANGUAGE_ID = ACV.LANGUAGE_ID ORDER BY S.count desc ]; nested exception is org.postgresql.util.PSQLException: The column name CREATED_AT was not found in this ResultSet."
IN THE ERROR SEEMS THIS FIELD ISN'T THERE SOMEHOW
If you have any idea what may be wrong or thing I can try please don't hesitate to comment, I would appreciate d even the smallest help thank you.
I can see there is an error in line 2 of the query - + "'" + statType.trim() + "' STATTYPE, ", right after the quote. STATTYPE does not have a table reference and is appended with a string. That could be another issue. I cannot comment on the question as I dont have enough reputation.

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"

Categories