JPA top one row that match criteria - java

Using JPA and need help with the same.
Current query looks as below
#Query("SELECT o FROM orders o " +
"WHERE (o.type = 'type1'... " +
" ) " +
" OR (o.type = 'type2' ...... " +
" ) "
)
Page<Order> getOrders(Pageable pageable);
to the above now I have to add another "OR" condition (type3 as below) for which I need to get only 1 record that match criteria i.e limit one only for this new OR condition.
Need to limit 1 for below criteria only
" OR (o.type = 'type3' ...... " +
" limit 1) "
how can I do that in JPA?

Related

HQL Hibernate query search check if list contains all elements of another list

I came across a problem that I cannot think of a solution.
So I got this piece of code:
public List<Post> getPosts(List<PostStrategy> allowedStrategyList, Set<Tag> allowedTags, int page, int resultsPerPage) {
return entityManager.createQuery("select post from Post post join post.tags tag where post.postStrategy in (:postStrategyList) and (:allowedTagsSize = 0 or tag in (:allowedTags))", Post.class)
.setParameter("postStrategyList", allowedStrategyList)
.setParameter("allowedTags", allowedTags)
.setParameter("allowedTagsSize", allowedTags.size())
.setFirstResult((page - 1) * resultsPerPage)
.setMaxResults(resultsPerPage)
.getResultList();
}
The problem with this piece of code is that when someone searches with more than one tag (for example: #video, #image), it returns both posts with two tags and one tag.
I would like it to return a post with both #video, and #image in its tags. For it to work, I somehow need to check if the list contains all elements of another list.
I searched for a solution for a while and tried different approaches so far, nothing.
I tried replacing "tag in (:allowedTags)" with "post.tags in (:allowedTags)" but that throws that my SQL is invalid.
Two years later I got my answer. I am now using Spring Boot and SpEL expressions so bear with me. This query does a little more than just my original idea but you can extract what you need from it.
#Override
#Query("select p from PostSnapshot p where " +
// Tags
"(:#{#query.withTags.size()} = 0 or p.id in (" +
"select post.id from PostSnapshot post inner join post.tags tag " +
"where tag.value in (:#{#query.withTags}) " +
"group by post.id " +
"having count(distinct tag.value) = :#{#query.withTags.size() * 1L}" +
")) and (:#{#query.withoutTags.size()} = 0 or p.id not in (" +
"select post.id from PostSnapshot post inner join post.tags tag " +
"where tag.value in (:#{#query.withoutTags}) " +
"group by post.id " +
"having count(distinct tag.value) = :#{#query.withoutTags.size() * 1L}" +
")) " +
// Artists
"and (:#{#query.withArtists.size()} = 0 or p.id in (" +
"select post.id from PostSnapshot post inner join post.artists artist " +
"where artist.preferredNickname in (:#{#query.withArtists}) " +
"group by post.id " +
"having count(distinct artist.preferredNickname) = :#{#query.withArtists.size() * 1L}" +
")) and (:#{#query.withoutArtists.size()} = 0 or p.id not in (" +
"select post.id from PostSnapshot post inner join post.artists artist " +
"where artist.preferredNickname in (:#{#query.withoutArtists}) " +
"group by post.id " +
"having count(distinct artist.preferredNickname) = :#{#query.withoutArtists.size() * 1L}" +
")) " +
// Title like words
"and lower(p.title) like concat('%', lower(:#{(#query.words.isEmpty()) ? '' : #query.words.toArray()[0]}) ,'%')" +
// OwnerId
"and p.ownerId = :ownerId")
Page<PostSnapshot> findAllByOwnerIdAndQuery(#Param("ownerId") UUID ownerId, #Param("query") PostQuerySearchDTO query, Pageable pageable);

Issue with JPQL request take long time to execute with more then 600000 registrations

I have a query in jpql that normally walk with a reduced data count, the problem is when the table to them over 600000 data records.
I use spring data, with an entity that contains no relation (no OneToMany, OneToOne, ManyToOne .....)with oracle as database..
I used JpaRepository, crudRepository, I even tried with JDBC directly, the return takes between 8 min up to 30 min.
I thought the problem was coming from the request, so I tried a findAll () and the processing time remained the same.
I changed the settings of the JVM -Xmx and -Xms to give more memory, but nothing helps.
Here is the request that I make:
public interface TestRepository extends CrudRepository {
#Query(value = "select new Test(CONCAT(t.date1, t.stringTarget, t.numInfo), t.name, t.phone, t.numInfo, t.date1, t.cotations, t.stringTarget, p.code, p.design)"
+ " from Test t, PointVente p"
+ " WHERE t.ePdv = p.numero"
+ " AND t.date1 BETWEEN :dateBegin AND :dateEnd"
+ " AND (t.state <> 'ANCL' or t.state is null)"
+ " AND t.game in :game"
+ " AND t.type in :type"
+ " AND t.participe = 1"
+ " AND NOT EXISTS (select t2.numInfo, t2.date1"
+ " from Test t2"
+ " WHERE t2.date1 BETWEEN :dateBegin AND :dateEnd"
+ " AND (t2.state <> 'ANCL' or t2.state is null)"
+ " AND t2.game in :game"
+ " AND t2.type in :type"
+ " AND t2.participe = 1"
+ " AND t2.numInfo = t.numInfo"
+ " AND t2.date1 = t.date1"
+ " AND (t2.phone is null or t2.phone NOT IN (select b.phone from BlacklistTest b))"
+ " group by CONCAT(t2.date1, t2.numInfo), t2.name, t2.phone, t2.numInfo, t2.date1, t2.ePdv"
+ " having sum(t2.cotations) <= :target)"
+ " AND t.cotations > :target"
+ " AND (t.phone is null or t.phone NOT IN (select b.phone from BlacklistTest b))")
List<TestResult> findTest(#Param("dateBegin") Date dateBegin, #Param("dateEnd") Date dateEnd, #Param("game") List<String> game, #Param("type") List<String> type, #Param("target") BigDecimal target);
}
is it possible to reduce the response time?
May I have your help please.

Spring data jpa failed to pass named parameters in native subquery for db2

Unable to pass named parameters in #NamedNativeQuery in spring data jpa
my repo:
#Query(value = "select stat.desc as desc," +
" stat.priority as priority," +
" (case when sum(activeUser) is null then 0 else sum(activeUser) end) as activeUser," +
" (case when sum(totalUser) is null then 0 else sum(totalUser) end) as totalUser" +
" from lookup.user stat left outer join" +
" (" +
" select user.role as role, " +
" sum (case when user.STATUS = 'ACTIVE' then 1 else 0 end) as activeUser," +
" count(*) as totalUser," +
" user.group as group" +
" from Ctrl.user user" +
" where user.group =:userGroup " +
" and user.branch_code =:branchCode " +
" group by user.role,user.group" +
" ) as tbl on stat.role = tbl.role and stat.group = tbl.group" +
" where stat.group =:userGroup " +
" group by stat.desc, stat.priority" +
"", nativeQuery = true)
public List<com.cimb.dto.UserStatusSummary> getSummaryReport(#Param(value = "userGroup") String userGroup, #Param(value = "branchCode") String branchCode);
The underlying database is DB2
When I tried to access that method I am hitting following error.
DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.25.13
if I hard code those named parameters with values then it's working.
I can not use jpql as real queries have some subqueries in it, so I cant use JPQL
Edit Update
After some digging, I have found out that, the parameters I am passing are in the subquery, since JPA don't have subquery concept it's not injecting into named parameters which resulting in a syntax error.
Now how to work with Subqueries in JPA
Please help.

Hibernate Query, how to use like or = on where clause depend on value passed

I have the following code and query :
String kodeCustomer, kodeDropship, kodeSales, kodePengirim;
kodeCustomer = kodeCustomerTextField.getText().trim();
kodeDropship = kodeDropshipTextField.getText().trim();
kodeSales = kodeSalesTextField.getText().trim();
kodePengirim = pengirimTextField.getText().trim();
... some other code ...
record = session.createQuery("from PenjualanTableDb where"
+ " dtanggalpenjualan >= :dawalParm"
+ " and dtanggalpenjualan < :dakhirParm"
+ " and coalesce(ckodecustomer,'') like :custParm"
+ " and coalesce(ckodedropship,'') like :dropshipParm"
+ " and coalesce(ckodesalesperson,'') like :salesParm"
+ " and coalesce(ckodepengirim,'') like :pengirimParm")
.setParameter("dawalParm", tanggalMulaiTrx)
.setParameter("dakhirParm", tanggalAkhirTrx)
.setParameter("custParm", kodeCustomer + "%")
.setParameter("dropshipParm", kodeDropship + "%")
.setParameter("salesParm", kodeSales + "%")
.setParameter("pengirimParm", kodePengirim + "%")
.list();
how to modify the query so it can give the correct output based on user input.
if textfield empty then the query using like, but if textfield not empty then query using =
Is there an easy way to handle that?
Thanks in advance
I think you should construct the hql query (including parameters) dynamically according to the parameters present instead of using "a like%".
record = session.createQuery("from PenjualanTableDb where"
+ " dtanggalpenjualan >= :dawalParm"
+ " and dtanggalpenjualan < :dakhirParm"
+ " and coalesce(ckodecustomer,'') like '%:custParm%'"
+ " and coalesce(ckodedropship,'') like '%:dropshipParm%'"
+ " and coalesce(ckodesalesperson,'') like '%:salesParm%'"
+ " and coalesce(ckodepengirim,'') like '%:pengirimParm%'")
.setParameter("dawalParm", tanggalMulaiTrx)
.setParameter("dakhirParm", tanggalAkhirTrx)
.setParameter("custParm", kodeCustomer)
.setParameter("dropshipParm", kodeDropship)
.setParameter("salesParm", kodeSales)
.setParameter("pengirimParm", kodePengirim)
.list();

Pageable in JPA native query

I want to use pagination with a native query. I use for this this syntaxe as in this example : Spring Data and Native Query with pagination
and it's my query:
#Query(value="SELECT rownum() as RN, users.num, users .l_service,service.type_service, users.date, " +
"chambre.price," +
"price* ( case when(datediff(day,date_d,date_f)=0) then 1 " +
"else datediff(day,date_d,date_f) end ) as Montant," +
"case when (service.type_service='R') and datediff(day,date_d,date_f) >=21 " +
"then (21300+(datediff(day,date_d,date_f)-21)*200)" +
"else price*(case when(datediff(day,date_d,date_f)=0) then 1 else datediff(day,date_d,date_f)end) end AS Montant_final " +
" users.year, users.Etat, " +
" from chambre JOIN users ON chambre.code = users.type " +
"JOIN service on service.code = users.l_service " +
" WHERE users.Etat='V' and RN between ?#{ #pageable.offset -1} and ?#{#pageable.offset + #pageable.pageSize order by users.num",
countQuery ="select count(*) from users ",nativeQuery = true)
Page<Object> getStatistiques(Pageable pageable);
I get this error :
Cannot mix JPA positional parameters and native Hibernate positional/ordinal parameters
This is the solution I found to my problem:
#Query(value="SELECT * from (SELECT ROW_NUMBER() OVER (ORDER BY users.num) as RN, users.num, users .l_service,service.type_service, users.date, " +
"chambre.price," +
"price* ( case when(datediff(day,date_d,date_f)=0) then 1 " +
"else datediff(day,date_d,date_f) end ) as Montant," +
"case when (service.type_service='R') and datediff(day,date_d,date_f) >=21 " +
"then (21300+(datediff(day,date_d,date_f)-21)*200)" +
"else price*(case when(datediff(day,date_d,date_f)=0) then 1 else datediff(day,date_d,date_f)end) end AS Montant_final " +
" users.year, users.Etat, " +
" from chambre JOIN users ON chambre.code = users.type " +
"JOIN service on service.code = users.l_service " +
" WHERE users.Etat='V') AS STA where RN between ?#{ #pageable.offset -1} and ?#{#pageable.offset + #pageable.pageSize} order by STA.num",
countQuery ="select count(*) from users ",nativeQuery = true)
Page<Object> getStatistiques(Pageable pageable);
I share it with you perhaps it can help someone else!

Categories