Spring Boot how to receive in the Jpa Repository String[] and search in the postgres database the fields that contain the similar array and change it - java

I created the following code to receive the id of the field and change the string array that is there by removing the fields passed in the parameter, or if the fields received by the parameter have everything that was passed, delete that field in the given id.
The structure is something like:
{ 110: [ 'abc', 'def'}
When I pass the id of the field 110, and the array I want the elements that have in common in the array that I passed and what is in the field id 110 to be removed, using the postgres database
` #Modifying
#Query(
value = "WITH fields AS " +
"(SELECT ( " +
"CASE " +
"WHEN ( ( CAST( array_to_json( ARRAY [ ?2 ] ) AS JSONB) ) #> ( fields -> ?1 ) ) IS TRUE " +
"THEN fields - ?1 " +
"ELSE jsonb_set(fields, '{?1}', jsonb_delete(fields -> ?1, ?2 )) " +
"END " +
") AS current " +
"FROM customer " +
"WHERE jsonb_exists_any( fields -> ?1, ( CAST( ARRAY[ ?2 ] as TEXT[] ) ) )" +
") " +
"UPDATE customer SET fields = fields.current FROM fields WHERE jsonb_exists_any( fields -> ?1, ( CAST( ARRAY[ ?2 ] as TEXT[] ) ) )",
nativeQuery = true
)
void remove( String fieldId, Set< String > values );`
The structure is something like:
{ 110: [ 'abc', 'def'}
When I pass the id of the field 110, and the array I want the elements that have in common in the array that I passed and what is in the field id 110 to be removed, using the postgres database

Related

HQL QuerySyntaxException: unexpected AST node

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.

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
);

MyBatis annotation dynamic query with variable inside select and group

Is it possible for MyBatis select query to read variable value for Select and Group By commands? If it is possible so how should I put the aggregationKeys variable inside that places? (Look into the code):
#Select({"SELECT #{aggregationKeys}, SUM(value) " +
"FROM usage_counter WHERE " + /*zrobic mape i pociagnac to tak, ze: (#{zmyslona wartosc} IS NULL OR api_consumer) itd*/
"(#{apiConsumerIds} IS NULL OR #{apiConsumerIds} like '%,'||api_consumer||',%' ) AND " +
"(#{serviceIds} IS NULL OR #{serviceIds} like '%,'||service||',%' ) AND " +
"(#{rateplanIds} IS NULL OR #{rateplanIds} like '%,'||rateplan||',%' ) AND " +
"(#{dateFrom} IS NULL OR date >= #{dateFrom} ) AND " +
"(#{dateTo} IS NULL OR date <= #{dateTo} ) AND " +
"(#{statuses} IS NULL OR #{statuses} like '%,'||counter_status||',%' ) " +
"GROUP BY ||#{aggregationKeys}||"})
#Results({
#Result(property = "date", column = "date"),
#Result(property = "apiConsumerId", column = "api_consumer"),
#Result(property = "serviceId", column = "service"),
#Result(property = "value", column = "value")
})
List<AggregatedUsage> getAggregatedUsageCounters(#Param("aggregationKeys") String aggregationKeys, #Param("dateFrom") Date dateFrom, #Param("dateTo") Date dateTo, #Param("apiConsumerIds") String apiConsumerIds, #Param("serviceIds") String serviceIds, #Param("statuses") String statuses);
Edit: Or is it possible to do grouping by in Java streams by two or more values (max 4 in this particular case)?
Second Edit: - ok it is possible but I it makes stream very complicated and I think uneffective.

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)

HQL - Delete with JOIN error

Im trying to execute an HQL delete with join.. After soon searching I found that I need to create a query just like suggested HERE:
http://dasunhegoda.com/1093-you-cant-specify-target-table-table_name-for-update-in-from-clause/104/
This is my query:
dao.executeByHql(
"DELETE FROM FinalGradeResult e WHERE e.id IN "
+ "( SELECT id FROM "
+ "( SELECT x FROM FinalGradeResult x "
+ "where x.student.id = :studentId "
+ " AND x.classDiscipline IN " +
+ "(SELECT cd from ClassDiscipline cd "
+ " where cd.clazz.id = :clazzId ) ) as X )",
new HqlParameter("studentId", student.getId()),
new HqlParameter("clazzId", from.getId()));
But I keep getting this error:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token:( near line 1, column 94 [DELETE FROM xxxxxxxxxxxx.entity.FinalGradeResult e WHERE e.id IN ( SELECT id FROM ( SELECT x FROM xxxxxxxxxxxxxxx.entity.FinalGradeResult x where x.student.id = :studentId AND x.classDiscipline IN (SELECT cd from xxxxxxxxxxxxxxxx.entity.ClassDiscipline cd where cd.clazz.id = :clazzId ) ) as X )]
The error points out that the second ( is wrong, the one right after "SELECT id FROM"
EDIT I ve tried like this and same error occours:
dao.executeByHql(
"DELETE FROM FinalGradeResult e WHERE e.id IN "
+ "( SELECT id FROM "
+ "( SELECT x FROM FinalGradeResult x "
+ " where x.student.id = :studentId "
+ " AND x.classDiscipline.clazz.id = :clazzId )"
+ " as X )",
EDIT 2 : The query like this doesnt work because of the problem described on the link I've posted in this question:
dao.executeByHql(
"DELETE FROM FinalGradeResult e WHERE e.id IN " + "( SELECT x.id FROM FinalGradeResult as x "
+ " where x.student.id = :studentId " + " AND x.classDiscipline.clazz.id = :clazzId )",
new HqlParameter("studentId", student.getId()), new HqlParameter("clazzId", from.getId()));
The error is:
Caused by: java.sql.SQLException: You can't specify target table 'tb_final_grade_result' for update in FROM clause
SOLUTION
After trying everything out here's our conclusion:
We cant have only one query directly because we cant have joins on DELETE.
We cant have only 2 queries (one subquery) because we have a MYSQL BUG (described on the link provided)
We cant have 3 queries (2 subqueries) because we cant have a subquery in the FROM clause. That's why our second query doesn´t work (select * from (select ...)) is invalid.
So I decided to use NativeSQL to solve the problem:
dao.executeBySQL(
" delete from tb_final_grade_result where id in "
+ " (select * from ( select finalgrade1_.id from tb_final_grade_result finalgrade1_ cross join tb_class_discipline classdisci2_ "
+ " where finalgrade1_.id_class_discipline=classdisci2_.id and finalgrade1_.id_student= :studentId and classdisci2_.id_class= :clazzId ) as tmp )",
new HqlParameter("studentId", student.getId()), new HqlParameter("clazzId", from.getId()));
Special thanks to #scaisEdge
Why do you need to use in (select on the same table that you are deleting from? Can't you just put the condition in the where clause?
DELETE FROM FinalGradeResult e WHERE e.student.id = :studentId " + " AND e.classDiscipline.clazz.id = :clazzId )",
new HqlParameter("studentId", student.getId()), new HqlParameter("clazzId", from.getId()));
Also, I'm not sure what you are referring to with the parameter classDiscipline.clazz.id? Is classDiscipline some other entity with a field named clazz that is yet another entity? That's what the query seems to be saying.
The problem with your original query is that you are not allowed you have inner selects anywhere but in select and where clauses. Because HQL operates in terms of entities and not tables or columns, selecting from subsets of tables doesn't make sense. See here:
Note that HQL subqueries can occur only in the select or where clauses.
We had a similar issue in our project and I struggled for awhile to find a single query solution, but I'm afraid with MySQL it isn't possible due to HQL's language design.
The best I came up with was to first fetch the ids as a list, and then pass that list as a list parameter to your update. For you it might be something like:
Query idQuery = createQuery("select id from FinalGradeResult gr where gr.student.id = :studentId AND gr.classDiscipline IN (SELECT cd from ClassDiscipline cd where cd.clazz.id = :clazzId"));
//add parameters
List<Number> ids = query.list();
Query entityQuery = createQuery("delete from FinalGradeResult where id in (:ids)");
entityQuery.setParameterList("ids", ids);
query.executeUpdate()
could be the position of as X is wrong
and you are repeting x instead of column name ( set ***column_name*** with the proper column name)
"DELETE FROM FinalGradeResult e WHERE e.id IN "
+ "( SELECT id FROM
( SELECT ***column_name *** FROM FinalGradeResult x where x.student.id = :studentId AND x.classDiscipline IN
(SELECT cd from ClassDiscipline cd where cd.clazz.id = :clazzId ) as X) )",
If the sibquery don't work in hibernate then try with a simple query with join
DELETE FROM FinalGradeResult e
WHERE e.id in (
SELECT id FROM FinalGradeResult x
JOIN ClassDiscipline cd ON ( cd.cd.clazz.id = :clazzId
and x.classDiscipline = cd.ClassDiscipline )
WHERE x.student.id = :studentId);
SOLUTION
After trying everything out here's our conclusion:
We cant have only one query directly because we cant have joins on DELETE.
We cant have only 2 queries (one subquery) because we have a MYSQL BUG (described on the link provided)
We cant have 3 queries (2 subqueries) because we cant have a subquery in the FROM clause. That's why our second query doesn´t work (select * from (select ...)) is invalid.
So I decided to use NativeSQL to solve the problem:
dao.executeBySQL(
" delete from tb_final_grade_result where id in "
+ " (select * from ( select finalgrade1_.id from tb_final_grade_result finalgrade1_ cross join tb_class_discipline classdisci2_ "
+ " where finalgrade1_.id_class_discipline=classdisci2_.id and finalgrade1_.id_student= :studentId and classdisci2_.id_class= :clazzId ) as tmp )",
new HqlParameter("studentId", student.getId()), new HqlParameter("clazzId", from.getId()));

Categories

Resources