Check if an integer is in a jsonb list - java

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.

Related

JPA parameter outside a where clause

I would like to know if the is a way to build a JPA query with parameter outside of the where clause. This query works fine in my database manager.
There is my query :
#Query(value = "SELECT q.quote, q.author, q.display_at, count(ql.*) AS like, (SELECT '{:userUUID}'::uuid[] && ARRAY_AGG(ql.user_uuid)::uuid[]) AS liked " +
"FROM quotes q " +
"LEFT JOIN quotes_likes ql ON ql.quote_uuid = q.uuid " +
"WHERE display_at = :date " +
"GROUP BY q.quote, q.author, q.display_at;", nativeQuery = true)
Optional<QuoteOfTheDay> getQuoteOfTheDay(UUID userUUID, LocalDate date);
I have the following error when the query is called : ERROR: syntax error at or near ":"
By default, Spring Data JPA uses position-based parameter binding. We can also use named parameter with #Param annotation to give a method parameter a concrete name and bind the name in the query. As you are trying to use the named parameter try using the below snippet with #Param annotations.
Optional<QuoteOfTheDay> getQuoteOfTheDay(#Param("userUUID") UUID userUUID, #Param("date") LocalDate date);
ERROR: syntax error at or near means that you need to escape casting colons.
Every : needs to be replaced by \\:
(SELECT ARRAY[:userUUID]'\\:\\:uuid[] && ARRAY_AGG(ql.user_uuid)\\:\\:uuid[]) AS liked
OR use double colons
(SELECT ARRAY[:userUUID]::::uuid[] && ARRAY_AGG(ql.user_uuid)::::uuid[]) AS liked
OR use Cast instead of colons
(SELECT cast(ARRAY[:userUUID] as uuid[]) && cast(ARRAY_AGG(ql.user_uuid) as uuid[])) AS liked
The second problem is that you need to create an array with a query parameter.
Try ARRAY[:userUUID] instead of {:userUUID}
Full query example:
#Query(value = "SELECT q.quote, q.author, q.display_at, count(ql.*) AS like, (SELECT ARRAY[:userUUID]\\:\\:uuid[] && ARRAY_AGG(ql.user_uuid)\\:\\:uuid[]) AS liked " +
"FROM quotes q " +
"LEFT JOIN quotes_likes ql ON ql.quote_uuid = q.uuid " +
"WHERE display_at = :date " +
"GROUP BY q.quote, q.author, q.display_at;", nativeQuery = true)
Optional<QuoteOfTheDay> getQuoteOfTheDay(UUID userUUID, LocalDate date);
As you are trying to pass method parameters to the query using named parameters, We define these using the #Param annotation inside our repository method declaration.
Each parameter annotated with #Param must have a value string matching the corresponding JPQL or SQL query parameter name.
#Query(value = "SELECT q.quote, q.author, q.display_at, count(ql.*) AS like, (SELECT '{:userUUID}'::uuid[] && ARRAY_AGG(ql.user_uuid)::uuid[]) AS liked " +
"FROM quotes q " +
"LEFT JOIN quotes_likes ql ON ql.quote_uuid = q.uuid " +
"WHERE display_at = :date " +
"GROUP BY q.quote, q.author, q.display_at;", nativeQuery = true)
Optional<QuoteOfTheDay> getQuoteOfTheDay(#Param("userUUID") UUID userUUID,#Param("date") LocalDate date);
Refer this for more details on how to use the #Query annotation.

jpa order records descending and select first record

I have a spring boot app connected to oracle DB.
I am trying to order a list of records and select the top most record.
I wrote a JPA query as below but it fails.
#Query("SELECT id FROM UploadedFile uploadedFile "
+ "WHERE uploadedFile.p_file_type = 'branch' "
+ "and p_file_status='Processed' "
+ "and p_is_file_process_with_error = 0 "
+ "order by c_created_date desc "
+ "FETCH FIRST 1 rows only ")
public String findLatestBranchCodeFile();
The error received was
creating bean with name 'uploadedFileRepo': Invocation of init method
failed; nested exception is java.lang.IllegalArgumentException:
Validation failed for query for method public abstract
java.lang.String
com.rhb.pintas.repo.UploadedFileRepo.findLatestBranchCodeFile()!
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token:
FETCH near line 1, column 204 [SELECT id FROM
com.rhb.pintas.entities.UploadedFile uploadedFile WHERE
uploadedFile.p_file_type = 'branch' and p_file_status='Processed' and
p_is_file_process_with_error = 0 order by c_created_date desc FETCH
FIRST 1 rows only ] -> [Help 1]
The issue seems to be with fetch,not sure whats wrong.
It seems you are mixing HQL and native query dialects:
If this will be a naviveQuery (like most of the columns would mention), then replace the entity name with table name and add nativeQuery option. And because You are using only a single table, You can skip the alias name:
#Query("SELECT id FROM uploaded_file "
+ "WHERE p_file_type = 'branch' and p_file_status='Processed' and "
+ "p_is_file_process_with_error = 0 "
+ "order by c_created_date desc "
+ "FETCH FIRST 1 rows only ", nativeQuery = true)
public String findLatestBranchCodeFile();
If You want to keep it as a HQL, then replace all column names with entity property names, like p_file_type > fileType (I guess column names). Secondly You will need to pass a Pageable parameter, to replace Your 'Fetch first' statement.
You can find more materials here:
Bealdung
NativeQ
StackOverflow
You are trying to execute SQL query, in this case you need to add nativeQuery=true attribute to #Query annotation
UPD.
got confused because FETCH FIRST - is a SQL syntax, for JPA way please check another solution - it is possible to return list with at most one element.
I guess, you can try passing pagable to limit result set size and unlimit your query:
public String findLatestBranchCodeFile(Pageable pageable); // pass new PageRequest(0,1)

Spring JPA query with clause "where value in (select id from otherTable)"

I want to write a JPA query that extracts all my entities matching a simple condition (column=boolean value) and a more complex conditions, i.e. the entity ID shall be contained in another table. MyEntity has no relationship with this other table.
My not working guess is:
#Query(value =
"select msr " +
"from MyEntity msr " +
"where msr.archived=false " +
" AND msr.id in
(select sc.res from search_campaign_results sc
where search_campaign_id=:campaign)")
Page<MyEntity> findResultsNotAnalyzed(Pageable pr, #Param("campaign") Long campaign);
Of course the error is "search_campaign_results is not mapped", which is correct .
How can I fix this without writing a completely native query?

Use postgres function timestamp in JpaRepository

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

Spring jpa native query sorting adding prefix to order by field name

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

Categories