I need to use window functions within a Spring Data Repository, is
this possible?
I am now using java spring maven and I have no knowledge about the entity table partition in JPA.
My SQL Query
select
b.q_stop_id as q_stop_id,
b.q_work_day as q_work_day,
b.q_work_end as q_work_end,
b.q_mc_num as q_mc_num,
b.q_mc_name as q_mc_name,
b.Hnbn as q_hnbn,
b.q_koku as q_koku,
b.q_stop_st_time as q_stop_st_time,
b.q_stop_en_time as q_stop_en_time,
b.q_stop_time_s as q_stop_time_s,
b.q_stop_maj_code as q_stop_maj_code,
b.q_stop_major as q_stop_major,
b.q_stop_num as q_stop_num,
b.q_stop_minor as q_stop_minor,
b.q_pause_flag as q_pause_flag
from
(
select ROW_NUMBER() OVER (PARTITION BY a.rnk
ORDER BY a.q_stop_st_time,a.q_stop_en_time) AS RowNo,COUNT(*) OVER () as cnt,*
from (
select DENSE_RANK() OVER(PARTITION BY proL.q_set_hnbn ORDER BY stL.q_stop_st_time,stL.q_stop_en_time DESC) as rnk,case when proL.q_set_hnbn is not null and proL.q_set_hnbn !='' then proL.q_set_hnbn else proL.q_hnbn end as Hnbn ,proL.q_set_hnbn as setHnbn, stL.q_stop_id as q_stop_id,wk.q_work_day as q_work_day,wk.q_work_end as q_work_end,mc.q_mc_num as q_mc_num,mc.q_mc_name as q_mc_name,proL.q_hnbn as q_hnbn,proL.q_koku as q_koku,stL.q_stop_st_time as q_stop_st_time,stL.q_stop_en_time as q_stop_en_time,stL.q_stop_time_s as q_stop_time_s,mst.q_stop_maj_code as q_stop_maj_code,mst.q_stop_major as q_stop_major,mst.q_stop_num as q_stop_num,mst.q_stop_minor as q_stop_minor,
mst.q_pause_flag as q_pause_flag
from T_STOP_LOG stL inner join M_stop_item mst on stL.q_stop_num=mst.q_stop_num
inner join T_work_log wk on stL.q_work_id=wk.q_work_id
inner join T_prod_log proL on wk.q_work_id =proL.q_work_id
inner join M_mc mc on wk.q_mc_num=mc.q_mc_num
left join T_malfunction_repair_log r on r.q_stop_id=stL.q_stop_id
where wk.q_work_day >='2021-04-19 00:00:00.000' and
wk.q_work_end<='2021-04-20 23:59:59.000' and mc.q_mc_num='1200' )a
)b where b.RowNo=1 or b.RowNo=2
> I found the solution by using JPA nativeQuery = true
#Query(value = "select " + "b.q_stop_id as q_stop_id," + "b.q_work_day as q_work_day,"
+ "b.q_work_end as q_work_end," + "b.q_mc_num as q_mc_num," + "b.q_mc_name as q_mc_name,"
+ "b.Hnbn as q_hnbn," + "b.q_koku as q_koku," + "b.q_stop_st_time as q_stop_st_time,"
+ "b.q_stop_en_time as q_stop_en_time," + "b.q_stop_time_s as q_stop_time_s,"
+ "b.q_stop_maj_code as q_stop_maj_code," + "b.q_stop_major as q_stop_major,"
+ "b.q_stop_num as q_stop_num," + "b.q_stop_minor as q_stop_minor," + "b.q_pause_flag as q_pause_flag "
+ "from" + "(" + "select ROW_NUMBER() OVER (PARTITION BY a.rnk "
+ "ORDER BY a.q_stop_st_time,a.q_stop_en_time) AS RowNo,COUNT(*) OVER () as cnt,* "
+ "from (select DENSE_RANK() OVER(PARTITION BY proL.q_set_hnbn ORDER BY stL.q_stop_st_time,stL.q_stop_en_time DESC) as rnk,case when proL.q_set_hnbn is not null and proL.q_set_hnbn !='' then proL.q_set_hnbn else proL.q_hnbn end as Hnbn ,proL.q_set_hnbn as setHnbn,stL.q_stop_id as q_stop_id,wk.q_work_day as q_work_day,wk.q_work_end as q_work_end,mc.q_mc_num as q_mc_num,mc.q_mc_name as q_mc_name,proL.q_hnbn as q_hnbn,proL.q_koku as q_koku,stL.q_stop_st_time as q_stop_st_time,stL.q_stop_en_time as q_stop_en_time,stL.q_stop_time_s as q_stop_time_s,mst.q_stop_maj_code as q_stop_maj_code,mst.q_stop_major as q_stop_major,mst.q_stop_num as q_stop_num,mst.q_stop_minor as q_stop_minor,"
+ "mst.q_pause_flag as q_pause_flag "
+ "from T_STOP_LOG stL inner join M_stop_item mst on stL.q_stop_num=mst.q_stop_num "
+ "inner join T_work_log wk on stL.q_work_id=wk.q_work_id "
+ "inner join T_prod_log proL on wk.q_work_id =proL.q_work_id "
+ "inner join M_mc mc on wk.q_mc_num=mc.q_mc_num "
+ "left join T_malfunction_repair_log r on r.q_stop_id=stL.q_stop_id "
+ "where wk.q_work_day >=:workDay and wk.q_work_end<=:workEnd and mc.q_mc_num=:kiban)a "
+ ")b where b.RowNo=1 or b.RowNo=2", nativeQuery = true)
Related
I am trying to use this query in springboot so I can display the results in a webpage. I know that this query works because I tested it in postgresql and it gave me the right results.
But JPA is telling me that the '(' after the first FROM is an unexpected token and the query was therefore viewed as invalid.
This is my query:
#Query(
"SELECT com.example.imse22.model.TrvlA_Cust_Dto(books_query.name, count(travelA_query.customer_id)) " +
"FROM (SELECT DISTINCT customer_servant.employee_id, books.customer_id FROM customer_servant " +
"INNER JOIN books ON customer_servant.employee_id = books.customer_servant_id) AS travelA_query " +
"INNER JOIN " +
"(SELECT travel_agency.id, travel_agency.name, employee.employee_id FROM travel_agency " +
"INNER JOIN employee ON travel_agency.id = employee.travel_agency_id) AS books_query " +
"ON travelA_query.employee_id = books_query.employee_id " +
"GROUOP BY travelA_query.name")
can somebody help me out how I could rewrite the query so that JPA approves it?
Your query is native so you should declare it in that way:
#Query(
value = "SELECT com.example.imse22.model.TrvlA_Cust_Dto(books_query.name, count(travelA_query.customer_id)) " +
"FROM (SELECT DISTINCT customer_servant.employee_id, books.customer_id FROM customer_servant " +
"INNER JOIN books ON customer_servant.employee_id = books.customer_servant_id) AS travelA_query " +
"INNER JOIN " +
"(SELECT travel_agency.id, travel_agency.name, employee.employee_id FROM travel_agency " +
"INNER JOIN employee ON travel_agency.id = employee.travel_agency_id) AS books_query " +
"ON travelA_query.employee_id = books_query.employee_id " +
"GROUOP BY travelA_query.name", nativeQuery = true)
link point 2.2: https://www.baeldung.com/spring-data-jpa-query
Ok so this is how I solved it:
I changed my query into a native one just like #notAPPP pointed out and then I only had to add an alias for the LEFT JOIN (also I changed INNER JOIN to LEFT JOIN).
here the code example:
#Query(value = "SELECT combined.name as name, count(combined.customer_id) as id " +
"FROM (" +
"(SELECT travel_agency.name, travel_agency.id, employee.employee_id " +
"FROM travel_agency INNER JOIN employee ON travel_agency.id = employee.travel_agency_id) as trvlEmp " +
"LEFT JOIN " +
"(SELECT books.customer_id, books.customer_servant_id, customer_servant.employee_id " +
"FROM books INNER JOIN customer_servant ON books.customer_servant_id = customer_servant.employee_id) as custBooks " +
"ON trvlEmp.employee_id = custBooks.employee_id) as combined " + // this "AS combined" got added
"GROUP BY combined.name", nativeQuery = true)
This makes sense, because after a FROM clause one should wirte the name of a table or a result table (e.g. from two joined queries like in my case). As I didnt specify an alias for the LEFT JOIN of my two subqueries, JPA obviously didnt know how to handle the result of those subqueries. Therefore always name your subqueries if they are not used in a WHERE clause, but rather with a FROM clause, like in my case. E.g. the name I gave my LEFT JOIN is "combined" as seen in the code example above.
Also I changed my INNER JOIN to a LEFT JOIN to get the value 0 of the elements that have 0 counts of what I wanted to count in the table.
If you want to know how to handle the result which such a query returns follow this link.thorben-janssen.com/spring-data-jpa-dto-native-queries
I'm using JpaRepository and I'm creating a #Query in my repository:
this is my query:
#Query( "SELECT SUM(p.prima) as prima, p.producto as producto, p.tipoProducto as tipoProducto, p.compania as compania, p.cliente as cliente, p.vendedor as vendedor " +
"FROM Poliza p " +
"JOIN Producto pr ON p.producto=pr " +
"JOIN TipoProducto tp ON p.tipoProducto=tp " +
"JOIN Compania c ON p.compania=c " +
"JOIN Cliente cl ON p.cliente=cl " +
"LEFT JOIN Vendedor v ON p.vendedor=v " +
"WHERE p.comienzo >=?1 " +
"AND p.comienzo <= ?2 " +
"GROUP BY p.producto")
and I realize that I only get the rows where "Vendedor" is present.
I used the spring.jpa.show-sql=true property to check what was going on and I realize that the query is creating an inner join for each property in the SELECT STATEMENT
inner join producto producto1_ on (poliza0_.producto=producto1_.id)
inner join tipo_producto tipoproduc2_ on (poliza0_.tipo_producto=tipoproduc2_.id)
inner join compania compania3_ on (poliza0_.compania=compania3_.id)
inner join cliente cliente4_ on (poliza0_.cliente=cliente4_.id)
inner join vendedor vendedor5_ on (poliza0_.vendedor=vendedor5_.id)
join producto producto6_ on poliza0_.producto=producto6_.id
join tipo_producto tipoproduc7_ on poliza0_.tipo_producto=tipoproduc7_.id
join compania compania8_ on poliza0_.compania=compania8_.id
join cliente cliente9_ on poliza0_.cliente=cliente9_.id
left join vendedor vendedor10_ on poliza0_.vendedor=vendedor10_.id
As you can see in the first part I have an inner join from Vendedor which makes the query wrong.
How should I create my query to get the expected result?
if understand clearly
#Query( "SELECT SUM(p.prima) as prima, p.producto as producto, p.tipoProducto as tipoProducto, p.compania as compania, p.cliente as cliente, p.vendedor as vendedor " +
"FROM Poliza p " +
"JOIN Producto pr ON p.producto=pr " +
"JOIN TipoProducto tp ON p.tipoProducto=tp " +
"JOIN Compania c ON p.compania=c " +
"JOIN Cliente cl ON p.cliente=cl " +
"LEFT JOIN Vendedor v ON p.vendedor=v " +
"WHERE p.comienzo >=?1 " +
"AND p.comienzo <= ?2 " +
"GROUP BY p.producto")
i think you can using v instead p.vendedor as vendedor in select field.
If I read correctly, you are defining your own query. So, you can edit the JOIN in your query and write LEFT JOIN instead.
Am I right on your intentions?
I have working query in PostgreSQL:
select s.id, s.seat_number as available_seat, s.row_number as available_row, rm.room_name as screening_room
from seats s
join rooms rm on rm.id=s.room_id
left join (
select r.seat_id from reserved_seats r
join reservations res on res.id=r.reservation_id AND res.screening_id = 3 ) res on res.seat_id=s.id
where res.seat_id is null AND s.room_id=3
ORDER BY s.id;
But I make mistakes translating it into the JPA query language.
Can I use nested SELECTs in JPQL?
The answer is to use native query:
#Query(value =
"SELECT s.id seatId, s.seat_number availableSeat, " +
"s.row_number availableRow, rm.name screeningRoom \n" +
"FROM seats s\n" +
"JOIN rooms rm on rm.id=s.room_id\n" +
" LEFT JOIN (\n" +
" SELECT r.seat_id FROM reserved_seats r\n" +
" JOIN reservations res ON res.id=r.reservation_id " +
" AND res.screening_id = :screeningId) res ON res.seat_id=s.id\n" +
"WHERE res.seat_id IS NULL AND s.room_id=:roomId AND s.row_number=:rowNumber\n" +
"ORDER BY s.id;", nativeQuery = true)
The answer is to use native query:
#Query(value =
"SELECT s.id seatId, s.seat_number availableSeat, " +
"s.row_number availableRow, rm.name screeningRoom \n" +
"FROM seats s\n" +
"JOIN rooms rm on rm.id=s.room_id\n" +
" LEFT JOIN (\n" +
" SELECT r.seat_id FROM reserved_seats r\n" +
" JOIN reservations res ON res.id=r.reservation_id " +
" AND res.screening_id = :screeningId) res ON res.seat_id=s.id\n" +
"WHERE res.seat_id IS NULL AND s.room_id=:roomId AND s.row_number=:rowNumber\n" +
"ORDER BY s.id;", nativeQuery = true)
I have a SQL query for get two table of SELECT.
I want to get two table as entity in result.
these tables are some column's name is equal(id,version).
I have following code :
String sql = "select sepTemp.*,pspTerm.* " +
"from SEPTRANSACTIONTEMP sepTemp " +
"LEFT JOIN PSP_Terminal pspTerm ON (pspTerm.idInPSP=sepTemp.termid AND pspTerm.pspID=:pspID) " +
"where NOT EXISTS " +
"(select * from PSPTRANSACTION pspTrans where pspTrans.PSPID=:pspID AND pspTrans.termNo=sepTemp.rrn) ";
List<Object[]> sepTransactionTemps = em.createNativeQuery(sql)
.setParameter("pspID", PSPTypes.SEP.getType())
.getResultList();
sepTransactionTemps.forEach(row -> {
SEPTransactionTemp sepTransactionTemp = ((SEPTransactionTemp) row[0]);
PSPTerminal sepTransactionTemp = ((PSPTerminal) row[1]);
...
but throw exception following :
org.hibernate.loader.custom.NonUniqueDiscoveredSqlAliasException: Encountered a duplicated sql alias [ID] during auto-discovery of a native-sql query
column id exists in your tables (SEPTRANSACTIONTEMP, LEFT JOIN PSP_Terminal)
create an alias for id column in your select query
String sql = "select " +
"sepTemp.id as sepTemp_id, " +
"sepTemp.version as sepTemp_version, " +
"pspTerm.id as pspTerm_id, " +
"pspTerm.version as pspTerm_version " // try here add all your column names
+ " from SEPTRANSACTIONTEMP sepTemp LEFT JOIN PSP_Terminal pspTerm "
+ "ON (pspTerm.idInPSP=sepTemp.termid AND pspTerm.pspID=:pspID) " + "where NOT EXISTS "
+ "(select * from PSPTRANSACTION pspTrans where pspTrans.PSPID=:pspID AND pspTrans.termNo=sepTemp.rrn) ";
List<Object[]> sepTransactionTemps = em.createNativeQuery(sql).setParameter("pspID", PSPTypes.SEP.getType())
.getResultList();
I have this Query in my JPA repository - and it works EXCEPT the " order by " part. Am i doing this wrong ? is it different in hql ?
#Query(value = "select wm.WagerIdentification, wm.BoardNumber, wm.MarkSequenceNumber, wm.MarkNumber," +
" pt.CouponTypeIdentification, pt.WagerBoardQuickPickMarksBoard " +
"from WagerBoard wb " +
"inner join wb.listOfWagerMarks wm " +
"inner join wb.poolgameTransaction pt " +
"where wb.WagerIdentification = wm.WagerIdentification and wb.BoardNumber = wm.BoardNumber and wb.GameIdentification = wm.GameIdentification and wm.meta_IsCurrent = 1 " +
"and wb.TransactionIdentification = pt.TransactionIdentification and pt.meta_IsCurrent = 1 " +
"and wb.meta_IsCurrent = 1 order by wm.WagerIdentification asc, wm.BoardNumber asc, wm.MarkNumber asc")
Instead of ordering result within the #Query, you can add a method parameter of type Sort, like in Spring Data JPA reference