HQL QuerySyntaxException: unexpected AST node - java

Searched and found a lot of questions about this but nothing for my particular case. I am getting an error on my HQL query, here is the code:
final Query query = session.createQuery(
" SELECT DISTINCT e " +
" FROM Employee e" +
" INNER JOIN Requisition r on r.supervisor = e.id " +
" WHERE r.status = 'Open' " +
" AND r.isEvergreen = false " +
" AND r.isConfidential = false " +
" AND r.employmentType != 'Intern (Fixed Term)' " +
" AND (" +
" CASE WHEN :searchString IS NOT NULL THEN (CONCAT(e.firstName, ' ', e.lastName) LIKE CONCAT('%', TRIM(:searchString), '%')) END)" +
" ORDER BY e.firstName, e.lastName")
.setParameter("searchString", searchString);
And here's the error log:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: CASE near line 1, column 329 [ SELECT DISTINCT e FROM <Insert the rest of the query>
The query works if I remove the CASE WHEN statement in the final AND and the setParameter. So that means something is wrong with the final AND (...) and/or the newly introduced parameter.
I am new to Hibernate and am struggling with this since the error message isn't super helpful. Any ideas?

The case you have does not complete the condition.
You can simplify the case as follows :
(coalesce(:searchString,1,0) =1 OR e.firstName||' '|| e.lastName LIKE '%'||:searchString||'%')
The first coalesce will check if searchstring is null , if it is will return 1 and 0 if it is not.
If it returns 1 , the expression after OR will not get evaluated.
If first expression return 0 , the expression after OR will be evaluated
This will fulfill your usecase to apply searchString filter only when it is not null.

Related

WITH Recursive query is not working when run using entityManager native query

I'm running this PostgreSQL query on Java and it is throwing an error "ERROR: syntax error at or near ":".
But the query is working on Postgresql when I run directly.
I'm thinking Array[]::integer[] is causing the issue. Can someone has any idea?
String query = "WITH RECURSIVE tree AS ( SELECT id, ARRAY[]::integer[] AS ancestors \n" +
" FROM regions \n" +
" WHERE parent_id IS NULL\n" +
" UNION ALL \n" +
" SELECT soato.id, tree.ancestors || regions.parent_id \n" +
" FROM regions, tree \n" +
" WHERE regions.parent_id = tree.id \n" +
") \n" +
" SELECT d.id FROM department d \n" +
" WHERE d.region_id IN (select id from tree where 1703 = ANY(tree.ancestors))";
Query q = entityManager.createNativeQuery(query);
q.getResultList();
Use an explicit cast to avoid the implicit PostgreSQL option :: for casting.
ARRAY[CAST(NULL AS INTEGER)] AS ancestors

Jpa native query doesnt work with group by case/when statement with binding values

Iam trying to use Jpa repository to get data from my sql server using a native query
This is a simple call from my service
repo.testData("h3","h3");
This is my repository query.
Select statement can read the binding variable :level but group by is unable to read it.
#Query(value="SELECT sum(pos.total_weekly_sales) as curr_yr_sales, sum(pos.total_weekly_qty) as curr_yr_qty, pos.vendor_nbr,pos.gmm_id,\n" +
"case \n" +
"when :level = 'h3' then pos.category_id\n" +
"else 0\n" +
"end category_id\n" +
"from dbo.agg_sams_data pos\n" +
"join dbo.calendar_dim cal on pos.wm_year_wk_nbr = cal.wm_year_wk_nbr\n" +
"WHERE \n" +
"cal.calendar_date BETWEEN '2019-09-11' and '2020-09-09'\n" +
"and pos.vendor_nbr = 68494\n" +
"and pos.gmm_id = 45\n" +
"and (:h3Flag = 'N' or pos.category_id = 52)\n" +
"GROUP by pos.vendor_nbr,pos.gmm_id,\n" +
"case \n" +
"when :level='h3' then pos.category_id\n" +
"else 0\n" +
"end",nativeQuery = true)
List<List<Double>> testData(String level,String h3Flag);
And i get the following error
com.microsoft.sqlserver.jdbc.SQLServerException: Column 'dbo.agg_sams_data.category_id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
If i pass the hardcoded value in the group by clause it works fine(as below)
"GROUP by pos.vendor_nbr,pos.gmm_id,\n" +
"case \n" +
"when 'h3'='h3' then pos.category_id\n"
You should try putting pos.category_id into the group by instead of the whole case when statement. The problem is, that SQL Server can't be sure that the parameter in both cases will have the same value so the expressions could be different.

How to get data based on 'AND' operator instead of 'LIKE' by using JpaSpecificationExecutorWithProjection's findAll method?

I am new to Hibernate.My senior used 'findAll' method of JpaSpecificationExecutorWithProjection (interface) which is returning result based on a 'LIKE' operator but I required result based on 'AND' operator. Please guide me how I can solve this?.
Below is the part of code which displays it is hitting query based on 'LIKE' operator
where
(
upper(course0_.course_subject) like ?
)
and (
upper(course0_.course_sub_category) like ?
)
and course0_.course_status=?
and (
upper(course0_.course_exam_segment) like ?
)
and (
upper(course0_.course_category) like ?
)
It is using AND operator. The LIKE is for evaluating your individual params.
If you don't like the JPA-methodqueries, you can always write your own in your repository. Below is a quick example incorporating a left join and returning a Page-object. Please take a look here for some basic JPQL
#Query("SELECT p FROM Product p "
+ "LEFT JOIN p.categories category "
+ "WHERE UPPER(p.name) LIKE UPPER(CONCAT('%', COALESCE(:searchRequest, ''), '%')) "
+ "AND UPPER(p.description) LIKE UPPER(CONCAT('%', COALESCE(:description, ''), '%')) "
+ "AND p.price BETWEEN :priceLow AND :priceHigh "
+ "AND p.averageRating >= :averageRating "
+ "AND p.archived = :archived "
+ "AND ((category.name IN :selectedCategories) "
+ "OR (:amountOfSelectedCategories = 0 AND category IN (SELECT c FROM Category c))) "
+ "GROUP BY p "
+ "HAVING SIZE(p.categories) >= :amountOfSelectedCategories"
)
Page<Product> findAllBySearchModel(
Pageable pageable,
#Param("searchRequest") String searchRequest,
#Param("description") String description,
#Param("priceLow") BigDecimal priceLow,
#Param("priceHigh") BigDecimal priceHigh,
#Param("averageRating") double averageRating,
#Param("archived") boolean archived,
#Param("selectedCategories") List<String> selectedCategories,
#Param("amountOfSelectedCategories") int amountOfSelectedCategories
);

H2 issues : request works in H2 console, not in jUnit test

I encounter a problem with H2 Database, I can't figure out what this problem is.
I'm working on a 3 alphanums code generator that should behave by incrementing by one the highest existing code (this is a SQL function that will be stored on the DB server).
The following code works perfectly in H2 console :
SELECT TOP 1 concat(a.Chr, b.Chr, c.Chr) AS REF
FROM
(VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M'),('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z')) a(Chr)
CROSS JOIN
(VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M'),('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z')) b(Chr)
CROSS JOIN
(VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M'),('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z')) c(Chr)
WHERE concat(a.Chr,b.Chr,c.Chr) > (
SELECT TOP 1
CASE
WHEN INSTRUCTION_CODE IS NULL
THEN ''
ELSE INSTRUCTION_CODE
END
FROM ACCOUNT
ORDER BY INSTRUCTION_CODE DESC
)
ORDER BY REF;
I need to implement this request in a Java jUnit test. Here is what I did :
public static ResultSet getReference(java.sql.Connection con) throws SQLException {
String query = "SELECT TOP 1 concat(a.Chr, b.Chr, c.Chr) AS REF "
+ "FROM "
+ "(VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M'),('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z')) a(Chr) "
+ "CROSS JOIN "
+ "(VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M'),('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z')) b(Chr) "
+ "CROSS JOIN "
+ "(VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M'),('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z')) c(Chr) "
+ "WHERE concat(a.Chr, b.Chr, c.Chr) > "
+ "(SELECT TOP 1 "
+ " CASE WHEN INSTRUCTION_CODE IS NULL "
+ " THEN '' "
+ " ELSE INSTRUCTION_CODE "
+ " END "
+ "FROM ACCOUNT order by INSTRUCTION_CODE DESC) "
+ "ORDER BY REF";
java.sql.ResultSet rs = con.createStatement().executeQuery(query);
return rs;
}
Here's the error message I get when playing it :
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "SELECT TOP 1 CONCAT(A.CHR, B.CHR, C.CHR) AS REF FROM (VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M'),('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z'))A([*]CHR) CROSS JOIN (VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M'),('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z'))B(CHR) CROSS JOIN (VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H'),('I'),('J'),('K'),('L'),('M'),('N'),('O'),('P'),('Q'),('R'),('S'),('T'),('U'),('V'),('W'),('X'),('Y'),('Z'))C(CHR) WHERE CONCAT(A.CHR, B.CHR, C.CHR) > (SELECT TOP 1 CASE WHEN INSTRUCTION_CODE IS NULL THEN '' ELSE INSTRUCTION_CODE END FROM ACCOUNT ORDER BY ACBS_PAYMENT_INSTRUCTION_CODE DESC) ORDER BY REF ";
Is there anything you see I didn't ?
Thanx
It looks like you use a recent version of H2 when you work with H2 Console, and some old version (1.4.196 or older) in your application.
Such old versions don't support the derived column list syntax. You need to use a more recent version in your application too.

Spring Data (REST) & #Query: optional list as param

I'm having the following function in one of my repositories:
#RestResource(path = "filter", rel = "filter")
#Query("SELECT t "
+ "FROM Trip t "
+ "WHERE "
+ "(:from IS NULL OR t.startTs >= :from) "
+ "AND (:categories IS NULL OR t.category IN :categories) ")
Page<Trip> filter(
#Param("from") Instant from,
#Param("categories") List<Category> categories,
Pageable pageable);
The Category is an enum which is stored as:
#Enumerated(EnumType.STRING)
in the Trips table.
When I'm doing my HTTP request with exactly one category I'm getting the correct results. Same behaviour when doing a request without categories key.
htt*://localhost/filter?categories=PRIVATE ==> ok
htt*://localhost/filter ==> ok
When using more than one category:
htt*://localhost/filter?categories=PRIVATE,BUSINESS
I'm getting the following exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST
node: {vector} [select count(t) FROM foo.bar.services.trips.model.Trip
t WHERE (:from IS NULL OR t.startTs >= :from) AND (:categories_0_,
:categories_1_ IS NULL OR t.category IN (:categories_0_,
:categories_1_)) ]
Anybody have an idea what I'm doing wrong here?
Try one of the following:
1) Try to enclose the statements involving the list in parentheses:
#Query("SELECT t "
+ "FROM Trip t "
+ "WHERE "
+ "(:from IS NULL OR t.startTs >= :from) "
+ "AND ((:categories IS NULL) OR (t.category IN :categories)) ")
2) Enclose the :categories in parentheses here
t.category IN (:categories)

Categories

Resources