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\"";
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
Iam trying to use Jpa repository to get data from my sql server using a native query
This is a simple call from my service
repo.testData("h3","h3");
This is my repository query.
Select statement can read the binding variable :level but group by is unable to read it.
#Query(value="SELECT sum(pos.total_weekly_sales) as curr_yr_sales, sum(pos.total_weekly_qty) as curr_yr_qty, pos.vendor_nbr,pos.gmm_id,\n" +
"case \n" +
"when :level = 'h3' then pos.category_id\n" +
"else 0\n" +
"end category_id\n" +
"from dbo.agg_sams_data pos\n" +
"join dbo.calendar_dim cal on pos.wm_year_wk_nbr = cal.wm_year_wk_nbr\n" +
"WHERE \n" +
"cal.calendar_date BETWEEN '2019-09-11' and '2020-09-09'\n" +
"and pos.vendor_nbr = 68494\n" +
"and pos.gmm_id = 45\n" +
"and (:h3Flag = 'N' or pos.category_id = 52)\n" +
"GROUP by pos.vendor_nbr,pos.gmm_id,\n" +
"case \n" +
"when :level='h3' then pos.category_id\n" +
"else 0\n" +
"end",nativeQuery = true)
List<List<Double>> testData(String level,String h3Flag);
And i get the following error
com.microsoft.sqlserver.jdbc.SQLServerException: Column 'dbo.agg_sams_data.category_id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
If i pass the hardcoded value in the group by clause it works fine(as below)
"GROUP by pos.vendor_nbr,pos.gmm_id,\n" +
"case \n" +
"when 'h3'='h3' then pos.category_id\n"
You should try putting pos.category_id into the group by instead of the whole case when statement. The problem is, that SQL Server can't be sure that the parameter in both cases will have the same value so the expressions could be different.
I need to execute an inner join on the same table. Below is the raw query I am currently executing.
String tagValueRowsSQL = "SELECT itv1.ItemTagValueID,itv1.FkItemID," +
"itv1.FkTagID,itv1.TagIndex,itv1.ValueIndex,itv1.Value,itv1.LastUpdateDateTime" +
" FROM tag.ItemTagValue itv1" +
" INNER JOIN tag.ItemTagValue itv2" +
" on itv1.fkTagID=" + tagIDsAndValues.get(LOCATION_STORE_CONFIG_TAG_NAME).getTagID() +
" and itv1.Value=" + storeId +
" and itv2.fkTagID = " + tagIDsAndValues.get(SENSOR_TYPE_TAG_NAME).getTagID() +
" and itv2.Value=" + sensorType;
RawSql rawSqlForSensorsInStoreAndOfType = RawSqlBuilder.parse(tagValueRowsSQL)
.columnMapping("itv1.ItemTagValueID", "ItemTagValueID")
.columnMapping("itv1.FkItemID", "FkItemID")
.columnMapping("itv1.FkTagID", "FkTagID")
.columnMapping("itv1.TagIndex", "TagIndex")
.columnMapping("itv1.ValueIndex", "ValueIndex")
.columnMapping("itv1.Value", "Value")
.columnMapping("itv1.LastUpdateDateTime", "LastUpdateDateTime")
.create();
Query<ItemTagValueModel> query = Ebean.find(ItemTagValueModel.class);
List<ItemTagValueModel> sensorsTagValueData = query.setRawSql(rawSqlForSensorsInStoreAndOfType).findList();
Executing the above using RawSQL seems pretty clumsy. How can I execute the above without using RawSQL? I checked this question Ebeans where columnA equals columnB in same table but I'm not sure how to apply that answer to my situation. Any help would be much appreciated.
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.
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.