JPA query additional group by - jpa

How to write JPA query for below SQL ?
select * from opstatus o where o.OPERATIONTYPE=2 and o.RECEIVEDFLAG =2 and o.SENDTIME in (select max(o1.SENDTIME)from opstatus o1 where (o1.OPERATIONTYPE=2 and o1.RECEIVEDFLAG =2) group by o1.dn);
Trying to run the below query
result = em.createQuery("select o from DTO o where "
+ "o.operationType=:operationType"
+ " and o.receivedFlag = :receivedFlag"
+ " and o.startTime in (select max(o1.startTime)from DTO o1 where
o1.receivedFlag = :receivedFlag group by o1.Dn) order by o.startTime").
setParameter("operationType","2").
setParameter("receivedFlag", "2").getResultList();
However during runtime below query gets genereated which has additional 'group by T2.DN' for which we get ' org.apache.openjpa.persistence.PersistenceException: ORA-00979: not a GROUP BY expression'
SELECT t0.OPERATIONID, t0.CURRENTSTEP, t0.DETAILEDSTEPS,t0.DN, t0.OPERATIONTYPE, t0.RECEIVEDFLAG, t0.REQUESTID, t0.SENDTIME FROM OPSTATUS t0, OPSTATUS t2 WHERE (t0.OPERATIONTYPE = ? AND t0.RECEIVEDFLAG = ? AND t0.SENDTIME IN (SELECT MAX(t1.SENDTIME) FROM OPSTATUS t1 WHERE (t1.OPERATIONTYPE = ? AND t1.RECEIVEDFLAG = ?) GROUP BY t1.DN)) GROUP BY t2.DN [params=?, ?, ?, ?]
How to prevent additional 'group by' getting appended ? I tried adding 'order by o.sendtime' no use .

Did you means select the last entry in every Dn group. If two different Dn have the same startTime and only one of it is the last(max) your query will fail. Because the o1 in the sub query not linked to the outer o, the OpenJPA will generate FROM OPSTATUS t0, OPSTATUS t2
Maybe you can change your query.
"select o from DTO o where "
+ "o.operationType=:operationType"
+ " and o.receivedFlag = :receivedFlag"
+ " and not exists (select o1 from DTO o1 where
o1.receivedFlag = :receivedFlag and o1.Dn = o.Dn and o1.startTime > o.startTime) order by o.startTime"

Related

Convert a Postgres query into JPQL

I have the following query in Postgres:
SELECT *
from table1
LEFT OUTER JOIN table1.table2 ON table1.latest_id = table2.id
WHERE table1.table2.status = 0
AND table1.id NOT IN (
(SELECT id from table3 where userId = table2.user))
I do not have the ability to join table1 and table3 and I am stuck writing the subquery in a format JPA will understand - working with a spring boot app. Here is where I got so far in my repository class:
#Query("SELECT c FROM #{#entityName} c JOIN FETCH c.table2 WHERE c.table2.status = 0")
fun findByIdAndStatus(id: String): MyEntity
I have attempted at the subquery as follows, but with no joy - there is a clear syntax error I cannot wrap my head around:
#Query("SELECT c FROM #{#entityName} c JOIN FETCH c.table2 WHERE c.table2.status = 0" AND c.id NOT IN (" +
"SELECT * FROM Table3 WHERE userId = c.table2.user")
Can you help?
Thank you
Assuming:
your SQL query doesn't utilize any input arguments
table1 is mapped by MyEntity and table3 is mapped by Table3 entity
entity associated with table2 is mapped in MyEntity using latest_id join column
status is mapped as a number (i.e Long / Integer)
You can rewrite the query to following JPQL form:
#Query("SELECT t1 FROM MyEntity t1 "
+ "JOIN t1.table2 t2 "
+ "WHERE t2.status = 0 AND t1.id NOT IN ("
+ " SELECT t3.id from Table3 t3 "
+ " WHERE t3.userId = t2.user "
+ ")")
List<MyEntity> findMyEntities();

Jpa Query Send part of Query as Parameter

i wan't query like this:
#Query(
nativeQuery = true,
value = "select vp.id , vp.identity, vp.vehicle_id, dt.i " +
"from vehicle_plate vp" +
" inner join (select max(vp2.id) as id, vp2.vehicle_id as vId from vehicle_plate vp2 group by vp2.vehicle_id) as vpg" +
" ON vp.id = vpg.id and vp.vehicle_id = vpg.vId" +
" cross join (values :dates ) dt(i)" +
"where vp.vehicle_id in (:vehicleIds)"
)
Page<Object[]> findAllJoinByDate(
#Param("dates") List<java.util.Date> dates,
#Param("vehicleIds") List<Integer> vehicleIds,
Pageable pageable
);
my problem is the part of query cross join (values :dates ) dt(i) and date parameter unknown by jpa.
should be same as
cross join (values ('2019-10-08') , ('2019-09-07') ) dt(i)
is there solution for this?

JPA is changing my query and giving me completely wrong results

I'm using EntityManager ("em") and creating a query using the method "createQuery", but it changes my query, If I use the method "createNativeQuery" it works fine, but than I can't add a list to parameters.
String query = " SELECT t0.id FROM Movie t0, Tagged t1, Tag t2 "
+ " WHERE t2.id = t1.tagfk AND t1.moviefk = t0.id AND t2.name in :tagList "
+ " GROUP BY t0.id HAVING count(distinct t2.id) = :size "
+ " ORDER BY count(t1) DESC, t0.popularity DESC";
Query q = em.createQuery(query, Integer.class);
q.setParameter("tagList", tagList);
q.setParameter("size", tagList.size());
q.setMaxResults(20);
result = (List<Integer>)q.getResultList();
The problem here is, when I print the query
System.out.println(q);
I got
SELECT t0.ID AS a1 FROM MOVIE t0, TAG t2, TAGGED t1 WHERE (((t2.ID = t1.TAGFK) AND
(t1.MOVIEFK = t0.ID)) AND (t2.NAME IN ?)) GROUP BY t0.ID
HAVING (COUNT(DISTINCT(t0.ID)) = ?) ORDER BY COUNT(t1.ID) DESC, t0.POPULARITY DESC LIMIT ? OFFSET ?"))
If you look closer, the:
HAVING count(distinct t2.id) = :size
became
HAVING (COUNT(DISTINCT(t0.ID)) = ?)
And obvious I got wrong result, it is checking the wrong table.
Is it a bug or I'm doing something wrong? I can't find why it is happening. thanks.
I solved it doing the follow:
First:
Update from JPA 2.0.X to 2.1.X
Second:
In the HAVING clause I added the column used in the SELECT and GROUP BY with a statement that doesn't interfere with anything:
HAVING t0.id IS NOT NULL AND count(distinct t2.id) = :size
The solution above does not work on 2.0.X, it will result in:
HAVING (COUNT(DISTINCT(t0.ID)) = ?) AND (COUNT(DISTINCT(t0.ID)) = ?)
weird!!!
I'm using Eclipse Link, I forgot to mention that.
It just works, but still, I'm not happy with the HAVING parser on JPA, it needs improvement.

Subquery in JPA

I am trying to write the following SQL query as a JPA query. The SQL query works (MySQL database) but I don't know how to translate it. I get a error token right after the first FROM. There are probably other errors here too because I was not able to find any guides on how to do sub-queries in the from part, aliasing and so on.
SQL query
SELECT tbl.* from (
SELECT u.*, COUNT(u.id) AS question_count FROM app_user AS u
INNER JOIN question AS q ON u.id = q.user_id GROUP BY u.id
) AS tbl ORDER BY tbl.question_count DESC LIMIT 10;
JPA query:
SELECT tbl FROM (SELECT u, COUNT(u.id) question_count FROM User u
INNER JOIN u.questions q ON u.id = q.user_id GROUP BY u.id) tbl
ORDER BY tbl.question_count LIMIT 10")
I can't test this with anything right now, but something along the lines of:
final String queryStr = "SELECT u, COUNT(u.id) FROM User u, Questions q WHERE u.id = q.user_id GROUP BY u.id ORDER BY COUNT(u.id) DESC";
Query query = em().createQuery(queryStr);
query.setMaxResults(10);
List<Object[]> results = query.getResultList(); //Index [0] will contain the User-object, [1] will contain Long with result of COUNT(u.id)

How to access a OnetoMany join table in JPQL?

I want to write a lttl complicated query in JPQL where i access a OneToMany Join table. I get QuerySyntaxException: Pan_PanRes is not mapped.
QUERY -
query = "SELECT p FROM Pan p WHERE p.id IN " +
"(SELECT p_id FROM Pan_PanRes p_prs WHERE prs_id IN " +
"(SELECT r.id FROM PRS r where r.pant = :pant))"+
" ORDER BY pr.clD"
i tried implementing this concept in MYSQL. It works fine. So i know i am not calling the join table in right way. How should it be called then?
I would like to add MYSQL statement which works fine -
mysql> select * from pan where id not in
(select pan_id from pan_panres where panres_id in
(select id from panres where pant_id = 3));
Thanks...
Solved it myself -
query = "SELECT p FROM Pan p WHERE p.id IN " +
"(SELECT p.id FROM p.panRes prs WHERE id IN " +
"(SELECT r.id FROM PanRes r where r.pant = :pant))"+
" ORDER BY pr.clD"
Where panRes is the oneToMany variable name i have used in Pan Class.