SQL query grammatical exception on converting recursive query to JPQL - sql

This is a JPQl query created from the below mentioned SQL query:
SELECT * FROM NursingSectionHead head where head.secCode IN (" +
"WITH NUR_SECTIONS_SEC_CODE (secCode) " +
"AS (SELECT secCode " +
"FROM NursingSection " +
"WHERE secCode = (SELECT loc.nursingSecCode FROM LocationMast loc WHERE loc.id.locCode = :locCode) " +
"UNION ALL " +
"SELECT C1.secCode " +
"FROM NursingSection C1 " +
"INNER JOIN NUR_SECTIONS_SEC_CODE C2 ON C1.prevSec = C2.secCode)" +
"SELECT * FROM NUR_SECTIONS_SEC_CODE)
This is the SQL query:
select * from IR_TB_NUR_SEC_HEAD head where HEAD.SEC_CODE IN (
WITH NUR_SECTIONS_SEC_CODE (SEC_CODE)
AS (
SELECT SEC_CODE
FROM IR_TB_NUR_SECTIONS
WHERE SEC_CODE = (select LOC.NURSING_SEC_CODE from mst_tb_location_mast loc where LOC.LOC_CODE = 20023)
UNION ALL
SELECT C1.SEC_CODE
FROM IR_TB_NUR_SECTIONS C1
INNER JOIN NUR_SECTIONS_SEC_CODE C2 ON C1.PREV_SEC = C2.SEC_CODE
)
SELECT *
FROM NUR_SECTIONS_SEC_CODE)
When executing it returns the below error:
"org.springframework.dao.InvalidDataAccessResourceUsageException:
could not extract ResultSet; SQL [n/a]; nested exception is
org.hibernate.exception.SQLGrammarException: could not extract
ResultSet"
What can I do about the above exception, please?

The "WITH" clause you are using is known as Common Table Expression (CTE) .I am pretty sure CTE is not supported by JPQL because if it is supported , no one will specially develop a library for supporting CTE query but only for Hibernate.
But you can switch to do use native SQL which should always work provided that your query can really be executed successfully against the database that you are using.

Related

JPQL: Switch/case when an object does not exist on the database

I am writing an #Query for a repository method. This query should return all Movie which have an average Rating less than the given parameters value:
#Query(value =
"select m from Movie m " +
"where (select avg(r.rating) from Review r " +
"where m.id = r.movie.id) < :rating")
List<Movie> findMoviesWithAverageRatingLowerThan(#Param("rating") Double rating);
The problem is that I have a requirement that when a Movie has no ratings, it should be interpreted as an average rating equal 0.
I have a clue that I should use switch/case combined with when, but as for now I have no idea how to do it.
Is this even possible to achieve this in one query?
You can try to use COALESCE expression like below:
#Query(value =
"select m from Movie m " +
"where (select avg(COALESCE(r.rating, 0)) from Review r " +
"where m.id = r.movie.id) < :rating")
List<Movie> findMoviesWithAverageRatingLowerThan(#Param("rating") Double rating);

SQL not ran by JDBC but perfectly functional in Database Clients

I have a query to select tree structure data from SQL Server 2012 to fetch tree structured resultset from one table.
This is the SQL I used:
with cte_child (id, parentId, contractId, contractName, jfCompany, jfDepartment, yfDepartment, totalAmount, signDate, lvl)
as
(
select
id, parentId, contractId, contractName,
jfCompany, jfDepartment, yfDepartment, totalAmount, signDate, 0
from
Contract_info_main
where
contractId = 'c2012-0412'
union all
select
c.id, c.parentId, c.contractId, c.contractName,
c.jfCompany, c.jfDepartment, c.yfDepartment, c.totalAmount,
c.signDate, s.lvl+1
from
Contract_info_main c
inner join
cte_child s on s.parentId = c.id
)
select * from cte_child
This SQL statement does run with correct result on local SQL Server 2012 database, as well as my local machine with DBeaver client. The driver used by DBeaver is "mssql-jdbc:7.4.1.jre8".
The weird thing is when I use pure Java code to send identical SQL string to send exactly same query, it fails with an error
object name 'Contract_inf_main' is invalid
Since I am using Ubuntu 18, I guess DLL along with Driver should not be a problem? but what could be possible cause of this problem? thanks
This is my JDBC code:
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
final Connection connection = DriverManager.getConnection("jdbc:sqlserver://192.168.5.158:1433", "general_reader", "sqlserver2017#reader");
final String sql = "with cte_child(id, parentId, contractId, contractName, jfCompany, jfDepartment, yfDepartment, totalAmount, signDate, lvl) " +
"as (select id, parentId, contractId, contractName, jfCompany, jfDepartment, yfDepartment, totalAmount, signDate, 0 " +
"from Contract_info_main where contractId = 'jy2012-041' " +
"union all select c.id, c.parentId, c.contractId, c.contractName, c.jfCompany, c.jfDepartment, c.yfDepartment, c.totalAmount, c.signDate, s.lvl+1 " +
"from Contract_info_main c inner join cte_child s on s.parentId = c.id) select * from cte_child";
final PreparedStatement statement = connection.prepareStatement(sql);
System.out.println(sql);
final ResultSet resultSet = statement.executeQuery();
while(resultSet.next()) {
System.out.println("id = " + resultSet.getString(1) + " and parentId = " + resultSet.getString(2));
}
resultSet.close();
statement.close();
connection.close();
}

difference in two tables Syntax error in SQL FROM Clause

I am trying to compare two tables with different columns.
I tried below code but it is giving syntax error
Syntax error:
"Exception thrown by code stage: Syntax error in FROM clause"
SELECT [Sheet1].[ID], [Sheet2].[ID_EXT] from [Sheet1], [Sheet2]
A As (SELECT [Sheet1].[ID], ([Sheet1].[Email] + ';' + [Sheet2].[Long Email]) as email from [Sheet1] inner join [Sheet2]
on [Sheet1].[ID] = FORMAT([Sheet2].[ID_EXT],'00000000000')
WHERE [Sheet2].[Type] = 3 AND UCase [Sheet1].[Email] <> UCase [Sheet2].[Long Email])
B As (SELECT [Sheet1].[ID], ([Sheet1].[Batchcode] + ';' + str([Sheet2].[Code])) as Code from [Sheet1] inner join [Sheet2] on [Sheet1].[ID] = FORMAT([Sheet2].[ID_EXT],'00000000000') WHERE [Sheet2].[Type]= 3 AND [Sheet1].[Batchcode]<>FORMAT([Sheet2].[Code],'0000))
SELECT [A].[ID], [A].[Email], [B].[Batchcode] from [A] Full outer join [A] ON [A].[ID]=[B].[ID_EXT]
Instead of A as (select...) you need , (select ... ) as A.

PostgreSQL joining multiple tables

Hi guys I am trying to join tables here, I want to add table called Table2 so that students from that table are displayed too. The thing which is confusing is I already have joins in this query, so how should add another join so that students from that Table2 are displayed as well, without breaking the existing code . Also, there is no way I can check output
The ID varables are stsidno in stTable 1, sidno in Table2, scsidno in table schedprd
Here's the code:
String selS = "select distinct stdistrict,stschool,stsidno,"
+ " sname as name,stgrade,"
+ "S.recnum as recnum, S.stldate as stldate,scsec,sctea,sccor,scgrade,scclsprd,scgrdprd,"
+ "case when P.scchangestartdate is null then C.clstart else "
+ "P.scchangestartdate end as scchangestartdate, "
+ "case when S.stedate is null or S.stedate<C.clstart "
+ "then C.clstart else S.stedate end as stedate "
+ "from stTable1 as S join schedprd as P on "
+ "(scyear=styear and scdistrict=stdistrict and scschool=stschool "
+ "and stsidno=scsidno and (scsec is not null and scsec<>'')) "
+ "left outer join calendar as C on (C.clyear=S.styear and "
+ "C.cldistrict=S.stdistrict and C.clschool=S.stschool and C.cltype='10') "
+ "where styear=? and stdistrict=? ";
You could UNION Table1 and Table2 together in a Common Table Expression (CTE) and then reference the CTE instead of Table1 in your query, like below:
WITH CTE
AS
(
SELECT *
FROM Table1
UNION
SELECT *
FROM Table2
)
select distinct
stdistrict,
stschool,
stsidno,
sname as name,
stgrade,
S.recnum as recnum,
S.stldate as stldate,
scsec,
sctea,
sccor,
scgrade,
scclsprd,
scgrdprd,
case when P.scchangestartdate is null then C.clstart else P.scchangestartdate end as scchangestartdate,
case when S.stedate is null or S.stedate<C.clstart then C.clstart else S.stedate end as stedate
from CTE as S
join schedprd as P on (scyear=styear and scdistrict=stdistrict and scschool=stschool and stsidno=scsidno and (scsec is not null and scsec<>''))
left outer join calendar as C on (C.clyear=S.styear and C.cldistrict=S.stdistrict and C.clschool=S.stschool and C.cltype='10')
where styear=? and stdistrict=?;

Sql Joins on multiple table returning product of two columns

I am trying to generate a report on a sql server database in asp.net and I am getting the results of some columns as a product of two columns. Here is the code
comm.CommandText = "SELECT Count(Courses.CourseID) AS CourseCount, Count(Students.StudentID) AS StudentCount, Schools.Name, Schools.StartDate, Schools.SchoolFees " +
"FROM Schools" +
"LEFT JOIN Courses ON (Schools.SchoolID = Courses.SchoolID)" +
"LEFT JOIN Students ON (Schools.SchoolID = Students.SchoolID) " +
"WHERE Schools.Active = 1 " +
"GROUP BY Schools.Name, Schools.StartDate, Schools.SchoolFees";
When I run the code, the result displays, but the columns for "CourseCount" and "StudentCount" display a value that is a product of each individual column. "CourseCount" is normally 288 and "StudentCount" is 38 but when I run the code, both "CourseCount" and "StudentCount" display 10944 which is 38 x 288.
Anyway I can make them display the correct values?
Changing your code from using a count of all rows, to a count of distinct values only, should return the results you expect
comm.CommandText = "SELECT Count(DISTINCT Courses.CourseID) AS CourseCount, Count(DISTINCT Students.StudentID) AS StudentCount, Schools.Name, Schools.StartDate, Schools.SchoolFees " +
"FROM Schools" +
"LEFT JOIN Courses ON (Schools.SchoolID = Courses.SchoolID)" +
"LEFT JOIN Students ON (Schools.SchoolID = Students.SchoolID) " +
"WHERE Schools.Active = 1 " +
"GROUP BY Schools.Name, Schools.StartDate, Schools.SchoolFees";
The results being returned are technically correct, if all schools have courses, and all courses have students
As stated above, it is how you are using the COUNT (), You are asking it to count all, which is why it returns so many. Use count on just the two values you want counted.
This might perform better than the DISTINCT Count method..
comm.CommandText =
"SELECT cc.CourseCount, sc.StudentCount, Schools.Name, Schools.StartDate, Schools.SchoolFees " +
"FROM Schools" +
"OUTER APPLY (SELECT Count(Students.StudentID) StudentCount FROM Students WHERE Students.SchoolID = Schools.SchoolID) sc " +
"OUTER APPLY (SELECT Count(Courses.CourseID) CourseCount FROM Courses WHERE Courses.SchoolID = Schools.SchoolID) cc " +
"WHERE Schools.Active = 1 ";