incorrect #query in spring boot - java

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

Related

Order By in #Query select not working

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

join fetch not working in Hibernate Query Language

I want to retrieve all the records in One database hit and for that, I am using join fetch statements below is my Query
String q = "SELECT oneChat from " + Chat.class.getName() + " oneChat "
+ " join fetch oneChat.user1 "
+ " join fetch oneChat.user2 "
+ " join fetch oneChat.user3 "
+ " join fetch oneChat.groupData "
+ "where oneChat.dmlStatus != :dmlStatusValue"
+ " AND group_id = :groupIdValue" + " AND reference_id = 0"
+ " AND root_chat_id = oneChat.chatId";
There are total 4 foreign keys/Joins in my table so I added the join fetch statement but its not working i.e. not returning anything how ever if I remove the join fetch statements I get the result set. My Fetch on table joins is by default Eager ( didn't changed it to Lazy).
Also there's no sql syntax error in the Log file. Am I missing anything ?
Update:
It is because the second join i.e. user2 is returning null so I wasn't getting any data. Now if anyone could tell me how can I counter this, the query should be independent it shouldn't rely on data.
IF you want to return results regardless of data being present on the dependencies, then you should use left join instead of inner join (join fetch is equal to inner join fetch):
"SELECT oneChat from " + Chat.class.getName() + " oneChat "
+ " left join fetch oneChat.user1 "
+ " left join fetch oneChat.user2 "
+ " left join fetch oneChat.user3 "
+ " left join fetch oneChat.groupData "
+ "where oneChat.dmlStatus != :dmlStatusValue"
+ " AND group_id = :groupIdValue" + " AND reference_id = 0"
+ " AND root_chat_id = oneChat.chatId";
Now when the OneChat does not have any user2 dependency on the database, the query will still return results regardless of that.
Just on the side.. if you are using prefixed, then try to add prefixes to group_id and root_chat_id fields in the where clause for clarity.

Mistake in HQL query while creating reports through hibernate projection

I had the following query working fine but then i had to convert it to hibernate projection for performance issues.
NamedQuery = " SELECT o FROM OrderJob o "
was converted to:-
String hqlQuery = "select "
+ "new JobAuditListVO( o.jobDate, o.jobType, customer.name, job.street, payment.description, p.paid,o.invoice) "
+ " from OrderJob o "
+ " join o.order ordr "
+ " join ordr.customer customer "
+ " join o.jobAddress job "
+ " join o.payment p"
+ " join p.paymentReceivedMethod payment";
getEntityManager().createQuery(hqlQuery).getResultList();
But the list is returning 0 results. While the name query return 2 results.
I have got the answer. Both the queries are absolutely equivalent.
The problem was that i had to use Left Join instead of Simple Join. Because some entities were returning null.

SQLite fails to find existing column in SELECT via JDBC and jOOQ

I experience some strange results working with SQLite and JDBC (via JOOQ actually, but this problem can be reproduced by executing the query string manually via JDBC). My database consists of a three tables including a many-to-many and one-to-many relationship. I try to select all values of the 'main' table and join all needed values out of the relationship tables:
SELECT location.name,
world.world,
player.player
FROM location
JOIN world
ON location."world-id" = world."world-id"
LEFT OUTER JOIN (location2player
JOIN player
ON location2player."player-id" = player."player-id")
ON location."location-id" = location2player."location-id"
Within JDBC this query fails:
java.sql.SQLException: [SQLITE_ERROR] SQL error or missing database (no such column: player.player)
When I execute the query in an external SQLite editor such as SQLite Manager for Firefox it works as expected.
I work with sqlite-jdbc-3.7.2 which I cannot change. For reference, the JOOQ query is:
create.select(LOCATION.NAME,WORLD.WORLD_,PLAYER.PLAYER_)
.from(LOCATION
.join(WORLD)
.on(LOCATION.WORLD_ID.eq(WORLD.WORLD_ID)
)
.leftOuterJoin(LOCATION2PLAYER
.join(PLAYER)
.onKey()
)
.on(LOCATION.LOCATION_ID.eq(LOCATION2PLAYER.LOCATION_ID)
)
.fetch()
Why fails this query in JDBC and how am I supposed to fix it?
While I think that you wrote valid ANSI SQL, it may well be that SQLite interprets your statement slightly differently. But you don't really need to nest joins the way you do. Try this insted:
SELECT location.name,
world.world,
player.player
FROM location
JOIN world
ON location."world-id" = world."world-id"
LEFT OUTER JOIN location2player
ON location."location-id" = location2player."location-id"
LEFT OUTER JOIN player
ON location2player."player-id" = player."player-id"
I was able to recreate your issue under sqlite-jdbc-3.7.2 using
sql =
"SELECT location.name, " +
"world.world, " +
"player.player " +
"FROM " +
"location " +
"JOIN world " +
"ON location.\"world-id\" = world.\"world-id\" " +
"LEFT OUTER JOIN (location2player " +
"JOIN " +
"player " +
"ON location2player.\"player-id\" = player.\"player-id\") " +
"ON location.\"location-id\" = location2player.\"location-id\"";
The problem appears to be that the location2player and player tables are "hidden" inside the parentheses () of the sub-join and are unavailable to the initial column list and the final ON clause. The following statement avoids that problem by giving the subquery an alias and using the alias name in those two places:
sql =
"SELECT " +
"location.name, " +
"world.world, " +
"playerlocation.player " +
"FROM " +
"location " +
"JOIN " +
"world " +
"ON location.\"world-id\" = world.\"world-id\" " +
"LEFT OUTER JOIN " +
"( " +
"SELECT location2player.\"location-id\", player.player " +
"FROM " +
"location2player " +
"JOIN " +
"player " +
"ON location2player.\"player-id\" = player.\"player-id\"" +
") AS playerlocation " +
"ON location.\"location-id\" = playerlocation.\"location-id\"";

HQL Left Outer Join for null column in one-to-one relation

Left outer join is supposed to get all data from left table no matter if there is matching record from B table, however if left tables right_id column is null, records cant be got.
I am explaining more
In Data model: Order.java, it is my LEFT table, there is a one to one relation
#OneToOne(targetEntity = OrderShippingDetail.class, optional=true, cascade = {CascadeType.ALL})
#JoinColumn(name = "SHIPPING_DETAIL_ID", referencedColumnName = "ID")
private OrderShippingDetail shippingDetail;
and HQL is:
hql = "SELECT " +
"o.id as id, " +
"o.createTime as createTime, " +
"o.customerEmailAddress as customerEmailAddress, " +
"o.customerPhoneNumber as customerPhoneNumber, " +
"o.customerNote as customerNote, " +
"o.invoicePrintedFlag as invoicePrintedFlag, " +
"shippingAddress.address.personName as shippingPersonName, " +
"shippingDetail.shippingCompany.id as shippingCompanyId, "+
"shippingDetail.shippingCompany.name as shippingCompanyName, "+
"shippingDetail.receiptNumber as shippingReceiptNumber, "+
"shippingDetail.trackingNumber as shippingTrackingNumber, "+
"shippingDetail.price as shippingPrice, "+
"o.invoiceNumber as invoiceNumber " +
"FROM Order AS o " +
"LEFT OUTER JOIN o.shippingAddress AS shippingAddress " +
"LEFT OUTER JOIN o.shippingDetail AS shippingDetail ";
But there comes just records which "SHIPPING_DETAIL_ID" is NOT null. Is there an error with HQL? It is created by modelling SQL command which is automatically created when hibernate runs.
I found this,
HQL supports two forms of association joining: implicit and explicit.
The queries shown in the previous section all use the explicit form,
that is, where the join keyword is explicitly used in the from clause.
This is the recommended form.
The implicit form does not use the join keyword. Instead, the
associations are "dereferenced" using dot-notation. implicit joins can
appear in any of the HQL clauses. implicit join result in inner joins
in the resulting SQL statement.
And I remove my dot notation in the SELECT part, so my new HQL:
hql = "SELECT " +
"o.id as id, " +
"o.createTime as createTime, " +
"o.customerEmailAddress as customerEmailAddress, " +
"o.customerPhoneNumber as customerPhoneNumber, " +
"o.customerNote as customerNote, " +
"o.invoicePrintedFlag as invoicePrintedFlag, " +
"shippingDetail, " +
"o.invoiceNumber as invoiceNumber " +
"FROM Order AS o " +
"LEFT OUTER JOIN o.shippingAddress AS shippingAddress " +
"LEFT OUTER JOIN o.shippingDetail AS shippingDetail ";
So, it works, it returns all records in Order table, however, I dont want to select all columns and relations in the ShippingDetail object. What can I do to solve this issue?
Add another explicit left join to the query:
SELECT o.id as id,
...,
shippingCompany.id as shippingCompanyId,
shippingCompany.name as shippingCompanyName,
...
FROM Order AS o
LEFT OUTER JOIN o.shippingAddress AS shippingAddress
LEFT OUTER JOIN o.shippingDetail AS shippingDetail
LEFT OUTER JOIN shippingDetail.shippingCompany AS shippingCompany

Categories

Resources