I have 3 queries:
// (1)
String sql = "SELECT tblClientInfo.ClientID, tblrefmarket.MarketDesc, tblclientinfo.LastName, tblledger.LoanAmount, "
+ "tblledger.DateStarted, tblledger.DailyPay, tblledger.Expiry FROM tblclientinfo Inner Join tblbusinessinfo ON tblbusinessinfo.ClientID = tblclientinfo.ClientID "
+ "Inner Join tblrefmarket ON tblbusinessinfo.MarketID = tblrefmarket.MarketID "
+ "Inner Join tblledger ON tblledger.ClientID = tblclientinfo.ClientID where MarketDesc = ?";
// (2)
String sumSQL = "SELECT ClientID, sum(tblloanpayment.AmountPaid) as sum FROM tblloanpayment where tblloanpayment.ClientID= ? ";
// (3)
String balSQL = "SELECT (SELECT tblLedger.LoanAmount from tblLedger WHERE tblLedger.ClientID = ?) - (SELECT SUM(tblLoanPayment.AmountPaid) "
+ "FROM tblLoanPayment WHERE tblLoanPayment.ClientID = ?) as balance FROM dual; ";
I have executed this 3 queries to display informations on a jTable. And it was successful.
Now my problem is when I am generating the report (or print) using JasperReports.
I can only display the 1st query since it is inside the database. While query 2 and 3 are not. They are just computations of the payments made in query 1.
How can I join this so that I can be able to display all necessary informations?
Here's my code:
private void cmdPrintActionPerformed(java.awt.event.ActionEvent evt) {
int row = tableMarket.getSelectedRow();
try {
JasperDesign jasperDesign = JRXmlLoader.load("notes receivables.jrxml");
String sql = "SELECT tblClientInfo.ClientID, tblrefmarket.MarketDesc, tblclientinfo.LastName, tblledger.LoanAmount, "
+ "tblledger.DateStarted, tblledger.DailyPay, tblledger.Expiry FROM tblclientinfo Inner Join tblbusinessinfo ON tblbusinessinfo.ClientID = tblclientinfo.ClientID "
+ "Inner Join tblrefmarket ON tblbusinessinfo.MarketID = tblrefmarket.MarketID "
+ "Inner Join tblledger ON tblledger.ClientID = tblclientinfo.ClientID where MarketDesc = '" + tableMarket.getModel().getValueAt(row, 0).toString() + "'";
JRDesignQuery newQuery = new JRDesignQuery();
newQuery.setText(sql);
jasperDesign.setQuery(newQuery);
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, null, conn);
JasperViewer.viewReport(jasperPrint);
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, e);
}
}
This code displays only the first query.
You are already selecting tblLedger.LoanAmount in your first query, so the only additional information required from both your second and third queries is sum(tblloanpayment.AmountPaid). Try:
SELECT c.ClientID,
m.MarketDesc,
c.LastName,
l.LoanAmount,
l.DateStarted,
l.DailyPay,
l.Expiry,
s.sumPaid,
l.LoanAmount - s.sumPaid as balance
FROM tblclientinfo c
Inner Join tblbusinessinfo b ON b.ClientID = c.ClientID
Inner Join tblrefmarket m ON b.MarketID = m.MarketID
Inner Join tblledger l ON l.ClientID = c.ClientID
left join (SELECT ClientID, sum(AmountPaid) as sumPaid
FROM tblloanpayment group by ClientID) s on c.ClientID = s.ClientID
where m.MarketDesc = ?
Remove the restriction by client id in the second and third queries. Make them into subselects (that is, put them in parentheses) and make a big select that joins all three subselects on client id.
Edit
So if the three queries are query1, query2, query3, you'd end up with
select ... from (query1) baseSql
join (query2) sumSql on baseSql.clientId = sumSql.clientId
join (query3) balSql on baseSql.clientId = balSql.clientId
You may need to use left join instead of join if there are rows in baseSql that are missing from sumSql or balSql.
Related
Currently I have such piece of code, which doesn't work, since I have to add schema name before each table in a query(like DEV.DASHBOARDS_METADATA):
public interface DashboardMetadataDao extends CrudRepository<DashboardMetadata, Integer> {
#Query("SELECT D FROM DASHBOARDS_METADATA D " +
"INNER JOIN FAC_DASHBOARDS_LINK DL ON D.ID = DL.DASHBOARD_ID " +
"INNER JOIN FIRMS F ON DL.FAC_ID = F.FAC_UNIT_ID " +
"INNER JOIN USERS U ON U.FIRM_ID = F.FIRM_ID WHERE LOWER(U.USERID) = LOWER(:userid)")
public Set<DashboardMetadata> findByUserId(#Param("userid") String userId);
}
The problem is that schema name differs from database to database (DEV/QA/PROD). Normally I use component's method which prepend schema's name to each table during query generation. How can do this using annotations?
Thanks!
Hibernate has a variable that can be used in native queries to get schema name called: {h-schema}
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/query/native/Native.html#sql-global-catalog-schema You can just put {h-schema}table in your query. I think you have to convert it to a native query.
Below Code Snippet worked for me
#Query(
value = "select *\n" +
"from {h-schema}TABLE-A r left join {h-schema}TABLE-B p on r.ID=p.ID\n" +
"left join {h-schema}TABLE-C pe on p.ID=pe.ID\n" +
"left join {h-schema}TABLE-D e on pe.ENT_ID=e.ENT_ID\n" +
"where r.role_type='Provisioning'",
nativeQuery = true)
I have the following code which is used to retrieve data from multiple tables (using joins) and then mapping every row into a DTOList but I also need to apply filters based on user preferences: per table1.name or table2.name, table3, etc.
So I just want to know what would be the best way to do it in terms of performance and best practices;
retrieving all rows and then apply the filters with lambdas (easier)
change the query to a dynamic query with Criteria or something else?
Any other solution=?
#Repository
public class ArchiveRepository {
#Autowired
EntityManager em;
String queryStr = "select wsr.id as sampleid, s.id as slideid, tb.name as batchname, k.lot_number as kitlot, " +
" 'STRING' as slidetype, tb.worklist_name as worklist, wsr.final_call as results, " +
" wa.final_pattern_ids as patterns, 'edited/yesno' as edited, wsr.last_modified_by as user, wsr.last_modified_date as time " +
" from slide s " +
" left join table2 tb on s.test_batch_id = tb.id " +
" left join table3 k on tb.kit_lot_id = k.id " +
" left join table4 w on s.id = w.slide_id " +
" left join tabl5 pw on pw.well_id = w.id " +
" left join tabl6 cw on cw.well_id = w.id " +
" left join tabl7 wsr on wsr.patient_well_sample_id = pw.id or wsr.control_sample_id = cw.id " +
" left join (select * from *** (other subselect)) wa on wa.well_sample_id = wsr.**id or wa.well_sample_id = wsr.**id " +
"where tb.state = 'STATENEEDED'";
public ArchiveDataListDTO getArchiveData(){
Query query = em.createNativeQuery(queryStr);
ArchiveDataListDTO archiveDataListDTO = new ArchiveDataListDTO();
List<Object[]> resultL = (List<Object[]>)query.getResultList();
for( Object[] o : resultL){
archiveDataListDTO.addArchiveDataRow(
new ArchiveDataDTO((String)o[0], String.valueOf(o[1]), (String) o[2], (String) o[3], (String) o[4], (String) o[5],
(String) o[6], (String) o[7], (String) o[8], (String) o[9], (String) o[10]));
}
return archiveDataListDTO;
}
}
**
note I struggled some with the code cause I wanted to apply #sqlresultsetmapping to avoid manual results mapping but it just didn´t work, most of the examples out there are when you have an entity in the DB but in this case I retrieve from many tables.**
Thanks so much
2 .- change the query to a dynamic query with Criteria or something else?
I ended up creating the query on the fly; depending on the filters I get from UI i assemble the query with Java and send it to DB, it´s easier since this required many tables...
This question already has answers here:
Jpa namedquery with left join fetch
(2 answers)
Closed 5 years ago.
I'm using spring data JPA and I want to write a SQL query in my repository.
I have a following SQL query (notice the LEFT JOIN):
SELECT * FROM institution LEFT JOIN
(select * from building_institutions where building_institutions.building_id = 1) as reserved_institutions
ON reserved_institutions.institutions_user_id = institution.user_id
WHERE reserved_institutions.institutions_user_id is null;
and i want to execute it in my InstitutionRepository which is as follows:
#Repository
public interface InstitutionRepository extends JpaRepository<Institution, Long>, PagingAndSortingRepository<Institution,Long> {
// doesn't work
//#Query("SELECT b.institutions as bi FROM Building b left join Institution i WHERE bi.building_id not in :id")
Page<Institution> findPotentialInstitutionsByBuildingId(#Param("id") Collection<Long> id, Pageable pageable);
// doesn't work
#Query(
value = "SELECT * FROM kits_nwt.institution LEFT JOIN\n" +
"(SELECT * FROM kits_nwt.building_institutions WHERE kits_nwt.building_institutions.building_id = ?1) AS reserved_institutions\n" +
"ON reserved_institutions.institutions_user_id = kits_nwt.institution.user_id\n" +
"WHERE reserved_institutions.institutions_user_id IS null ORDER BY ?#{#pageable}",
nativeQuery = true)
Page<Institution> findPotentialInstitutionsByBuildingId(Long userId, Pageable pageable);
}
So, I want to get all institutions which are not in building with certain ID (which I will send as a parameter).
Here is my current DB data:
Institutions:
Building institutions:
What I want: (in this query, the id is set on 1, for presentation purposes)
I have looked at many SO questions and answers (such as this one) but I haven't been able to figure out the solution.
So, how do I write this query so that I get what I want?
Edit 1:
#KevinAnderson Currently, I'm trying with:
#Query(
value = "SELECT username, password, description, location, title, user_id FROM (institution INNER JOIN user ON institution.user_id = user.id) LEFT JOIN\n" +
"(SELECT * FROM building_institutions WHERE building_institutions.building_id = 1) AS reserved_institutions\n" +
"ON reserved_institutions.institutions_user_id = kits_nwt.institution.user_id\n" +
"WHERE reserved_institutions.institutions_user_id IS null ORDER BY ?#{#pageable}",
nativeQuery = true)
Page<Institution> findPotentialInstitutionsByBuildingId(Long userId, Pageable pageable);
And I'm getting this exception:
MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE) FROM building_institutions WHERE building_institutions.building_id = 1) A' at line 2
Edit 2:
#StanislavL here it is:
The problem is that your query gets me the institution with ID 25 because it is in both building with ID 1 and building with ID 2. When you do a JOIN, you have 2 rows ON institution ID being 25 in both institution table and building_institutions table. Then, your WHERE condition removes one from those two rows and I get one row where instituiton ID is 25, and I don't want what.
Here is an image for the above:
Edit 3 - this question is not a duplicate because of the following:
My query is with pagination (I added "with pagination" to the question title)
I'm not using #NamedQuery but #Query
My mistake was that I didn't write countQuery parameter to the #Query annotation
I solved it...
The query needs to look like this:
#Query(
value = "SELECT * FROM \n" +
"(institution INNER JOIN user ON institution.user_id = user.id) \n" +
"LEFT JOIN \n" +
"(SELECT * FROM \n" +
"building_institutions \n" +
"WHERE building_id = :userId)\n" +
" AS reserved_institutions \n" +
"ON reserved_institutions.institutions_user_id = kits_nwt.institution.user_id \n" +
" where reserved_institutions.institutions_user_id IS null \n"
+ "ORDER BY ?#{#pageable}"
,
countQuery = "SELECT count(*) FROM \n" +
"(institution INNER JOIN user ON institution.user_id = user.id) \n" +
"LEFT JOIN \n" +
"(SELECT * FROM \n" +
"building_institutions \n" +
"WHERE building_id =:userId)\n" +
" AS reserved_institutions \n" +
"ON reserved_institutions.institutions_user_id = kits_nwt.institution.user_id \n" +
"where reserved_institutions.institutions_user_id IS null \n" +
"ORDER BY ?#{#pageable}",
nativeQuery = true)
Page<Institution> findPotentialInstitutionsByBuildingId(#Param("userId") Long userId, Pageable pageable);
I was getting the error at line 4 near WHERE, when my query looked like this:
#Query(
value = "SELECT username, password, description, location, title, user_id FROM (institution INNER JOIN user ON institution.user_id = user.id) LEFT JOIN\n" +
"(SELECT * FROM building_institutions WHERE building_institutions.building_id = 1) AS reserved_institutions\n" +
"ON reserved_institutions.institutions_user_id = kits_nwt.institution.user_id\n" +
"WHERE reserved_institutions.institutions_user_id IS null ORDER BY ?#{#pageable}",
nativeQuery = true)
Page<Institution> findPotentialInstitutionsByBuildingId(Long userId, Pageable pageable);
and that was because I didn't add the countQuery parameter to the #Query annotation.
Big thanks to all of you who tried to help.
I hope that I save someone else many hours of misery.
Cheers! :)
Using the following query, I get data from two tables in the db. But if COL5, is empty, do not display even data of(TABLE1). It should also display other data?
SQLiteDatabase db = mHelper.getReadableDatabase();
final List<Dettaglio1> dettagli1 = new ArrayList<Dettaglio1>();
String sql = "SELECT C._id, " +
"B.col1, " +
"B.col2, " +
"B.col3, " +
"B.col4, " +
"B.col5, " +
"B.col6, " +
"SUM(C.col01), " +
"C.col02, " +
"C.col03 " +
"FROM table1 B LEFT JOIN table2 C ON (B.col5 = C.col02)";
Cursor cur = db.rawQuery(tabella_conti, null);
while (cur.moveToNext()){
Dettaglio1 d01 = new Dettaglio1();
d01.id= cur.getString(0);
d01.col1= cur.getString(1);
d01.col2= cur.getDouble(2);
d01.col3= cur.getString(3);
d01.col4 = cur.getString(4);
d01.col5= cur.getString(5);
d01.col6 = cur.getString(6);
d01.col01 = cur.getDouble(7);
d01.col02 = cur.getString(8);
d01.col03= cur.getString(9);
dettagli1.add(d01);
}
cur.close();
db.close();
....
....
}
If you want to include NULL values you should use LEFT or RIGHT join like this:
... from table1 as B RIGHT JOIN table2 as C ON (B.col5 = C.col02)
If RIGHT join isn't supported on some platforms (thanks to #user3608814, see comments) use LEFT join and change order of tables:
... from table2 as C LEFT JOIN table1 as B ON (C.col02 = B.col5)
UpdateIf this doesn't help (when as you have written there is no data in table2 but you still need results) you should reorganize your data scheme:
Add explicit foreign key to table2 that links it to table1. Let it be table2.extID column. Then it's possible to query like this:
... from table1 as B LEFT JOIN table2 as C ON (B._ID = C.extID)
I write
String sql = "select candidate_skill.candidate_id from candidate_skill " +
"inner join skill on skill.id = candidate_skill.skill_id " +
"where skill_id in (:skillIdList) group by candidate_skill.candidate_id " +
"Having count(candidate_skill.candidate_id) = (select count(*) from skill where skill.id in (:skillIdList) )";
sql = sql.replace(":skillIdList", generateSkillIdList(skills));
Query query = session.createSQLQuery(sql);
List<Candidate> candidates = query.list();
It works good
second situation:
String sql = "select candidate_skill.candidate_id from candidate_skill " +
"inner join skill on skill.id = candidate_skill.skill_id " +
"where skill_id in :skillIdList group by candidate_skill.candidate_id " +
"Having count(candidate_skill.candidate_id) = (select count(*) from skill where skill.id in :skillIdList )";
Query query = session.createSQLQuery(sql).setParameterList("skillIdList", skills);
List<Candidate> candidates = query.list()
log:
Hibernate: select candidate_skill.candidate_id from candidate_skill inner join skill on skill.id = candidate_skill.skill_id where skill_id in (?, ?) group by candidate_skill.candidate_id Having count(candidate_skill.candidate_id) = (select count(*) from skill where skill.id in ?, ? )
it doesn't works
and third:
String sql = "select candidate_skill.candidate_id from candidate_skill " +
"inner join skill on skill.id = candidate_skill.skill_id " +
"where skill_id in :skillIdList group by candidate_skill.candidate_id " +
"Having count(candidate_skill.candidate_id) = (select count(*) from skill where skill.id in (:skillIdList) )";
Query query = session.createSQLQuery(sql).setParameterList("skillIdList", skills);
List<Candidate> candidates = query.list();
log:
Hibernate: select candidate_skill.candidate_id from candidate_skill inner join skill on skill.id = candidate_skill.skill_id where skill_id in (?, ?) group by candidate_skill.candidate_id Having count(candidate_skill.candidate_id) = (select count(*) from skill where skill.id in (?, ?) )
it works good
P.S. Pay attention to the Brackets around :skillIdList
if I use setParameterList("argument",value) and argument in query 2 times, then first time hibernate substitutes brackets and in second - none
The syntax of IN requires the brackets.
As of why the 3rd example is working, two guesses:
hibernate has a functionality to automatically append missing brackets, but somehow this doesn't extend to subqueries
the sql server executes the sub-select first, and then the other query becomes redundant with the parameters you've passed, and so is not executed.