Combining two JPA Spring query SQL queries - sql

I created 2 custom SQL queries to get my data from my PostgreSQL database. I made two queries with on minor change. The user ID part. with wd.id it returns all worker reports, but sometimes I need to get a specific worker report. Is there any way to combine the two queries?
#Query(value = "SELECT\n" +
"\twd.id as workDetailId,\n" +
" max(ua.name) as name,\n" +
" count(sw.id) as shiftCount,\n" +
" sum(sw.actual_work_duration) as workDuration,\n" +
" sum(sw.actual_shift_duration) as shiftDuration,\n" +
"\twd.salary as salary,\n" +
"\tmax(mi.name) as jobRelation\n" +
"FROM shift_worker sw\n" +
"JOIN user_acc ua ON ua.work_detail_id = sw.work_detail_id\n" +
"JOIN work_detail wd ON sw.work_detail_id = wd.id\n" +
"JOIN maintenance_item mi ON wd.job_relation_id = mi.id\n" +
"WHERE sw.work_detail_id = wd.id AND\n" +
" sw.actual_work_start_time > ?1 AND\n" +
" sw.actual_work_start_time < ?2 AND sw.actual_work_end_time IS NOT NULL\n" +
"GROUP BY wd.id", nativeQuery = true)
Page<UserShiftReport> findUserReports(LocalDateTime startDateTime, LocalDateTime endDateTime, Pageable pageable);
#Query(value = "SELECT\n" +
"\twd.id as workDetailId,\n" +
" max(ua.name) as name,\n" +
" count(sw.id) as shiftCount,\n" +
" sum(sw.actual_work_duration) as workDuration,\n" +
" sum(sw.actual_shift_duration) as shiftDuration,\n" +
"\twd.salary as salary,\n" +
"\tmax(mi.name) as jobRelation\n" +
"FROM shift_worker sw\n" +
"JOIN user_acc ua ON ua.work_detail_id = sw.work_detail_id\n" +
"JOIN work_detail wd ON sw.work_detail_id = wd.id\n" +
"JOIN maintenance_item mi ON wd.job_relation_id = mi.id\n" +
"WHERE sw.work_detail_id = ?1 AND\n" +
" sw.actual_work_start_time > ?2 AND\n" +
" sw.actual_work_start_time < ?3 AND sw.actual_work_end_time IS NOT NULL\n" +
"GROUP BY wd.id", nativeQuery = true)
Page<UserShiftReport> findUserReportByUserId(Long userId, LocalDateTime startDateTime, LocalDateTime endDateTime, Pageable pageable);

If you could merge the two methods keeping the userId parameter, pass a 0 userId where the you want generic results and assuming there will be no data with userId equal to 0, you can combine the queries as -
Where sw.work_detail_id = case when ?1 = 0 then wd.id else ?1 end
Essentially a "case when" syntax usage on the differing column in where clause in your queries.

Related

Use the same query for multiple tables

I have this two similar queries for different tables, one for loan_offers table and one for special_offers table
for loan_offers
#Query(
value = "SELECT " +
"CAST(o.id AS VARCHAR), o.user_id, " +
"o.partner_key, o.partner_name, " +
"o.originator_key, o.originator_name, " +
"o.type, o.response, " +
"COALESCE(lo.recommendation_score, 0) AS recommendation_score " +
"FROM offers o " +
"INNER JOIN loan_offers lo " +
"ON lo.offer_id = o.id " +
"WHERE o.created_at > EXTRACT(epoch FROM now() - INTERVAL '30' DAY) * 1000 " +
"AND o.user_id = ?1 " +
"ORDER BY recommendation_score DESC",
nativeQuery = true)
List<OffersResponse> fetchLoanOffers(String userId);
for special_offers
#Query(
value = "SELECT " +
"CAST(o.id AS VARCHAR), o.user_id, " +
"o.partner_key, o.partner_name, " +
"o.originator_key, o.originator_name, " +
"o.type, o.response, " +
"COALESCE(so.recommendation_score, 0) AS recommendation_score " +
"FROM offers o " +
"INNER JOIN special_offers so " +
"ON so.offer_id = o.id " +
"WHERE o.created_at > EXTRACT(epoch FROM now() - INTERVAL '30' DAY) * 1000 " +
"AND o.user_id = ?1 " +
"ORDER BY recommendation_score DESC",
nativeQuery = true)
List<OffersResponse> fetchSpecialOffers(String userId);
So my question is how not to write so much similar code, maybe by using UDF or there is a better solution.
Use a variable to declare which table you want and use the variable in the query string. Change the alias of the table to be the same and it looks like it'd be the same query.
I don't really recommend it though as they are different tables that could change and the circumstances for the need. Its better to have the defined query for its use in a business object or something.
But we do these things to save typing some times.

"ORA-00920: invalid relational operator" Error

select
ic.item_name,
lh.locn_brcd from_locn,
lh2.locn_brcd to_locn,
wl.from_container,
wl.to_container,
wl.units,
wl.prev_from_container_status prev_from_lpn_status,
wl.curr_from_container_status curr_from_lpn_status,
wl.prev_to_container_status prev_to_lpn_status,
wl.curr_to_container_status curr_to_lpn_status,
wl.work_batch_number,
wl.transaction_name,
wl.action,
wl.work_id,
wl.date_updated,
wl.source_updated,
wl.tote_number,
wl.chute
from m_work_log wl
LEFT join item_cbo ic on wl.item_id=ic.item_id
left join locn_hdr lh on wl.from_location_id = lh.locn_id
left join locn_hdr lh2 on wl.to_location_id = lh2.locn_id
where wl.action in (:action)
and trunc(wl.date_updated) between :start_date and :end_date
and (ic.item_name in (:list) OR
wl.source_updated = :username OR
wl.to_container in (:LPNList) OR
(:list is null and :username is null and :LPNList is null)
)
order by date_updated desc
Hi everyone,
when I run this code through Oracle SQL Developer and I add two items to the :list parameter and two items to the :action parameter it works fine. But when I run this through SSRS (report builder ) it fails to run and I get an "ORA-00920: invalid relational operator". I'm new to SQL and i'm not sure what I am doing incorrectly here. Any help is greatly appreciated. Thanks!
There are 2 ways to do this:
Multiple Value Parameter:
First of all, you must use Oracle provider, multiple value paramaters does not work with neither ODBC nor OLEDB connections (reference).
Here is an external link explaining in detail here.
Using an expression as the query by putting the whole thing like this ="query_here"
="select "
+ " ic.item_name,"
+ " lh.locn_brcd from_locn,"
+ " lh2.locn_brcd to_locn,"
+ " wl.from_container,"
+ " wl.to_container,"
+ " wl.units,"
+ " wl.prev_from_container_status prev_from_lpn_status,"
+ " wl.curr_from_container_status curr_from_lpn_status,"
+ " wl.prev_to_container_status prev_to_lpn_status,"
+ " wl.curr_to_container_status curr_to_lpn_status,"
+ " wl.work_batch_number,"
+ " wl.transaction_name,"
+ " wl.action,"
+ " wl.work_id,"
+ " wl.date_updated,"
+ " wl.source_updated,"
+ " wl.tote_number,"
+ " wl.chute"
+ "from m_work_log wl"
+ " LEFT join item_cbo ic on wl.item_id=ic.item_id"
+ " left join locn_hdr lh on wl.from_location_id = lh.locn_id"
+ " left join locn_hdr lh2 on wl.to_location_id = lh2.locn_id"
+ "where wl.action in (:action)"
+ " and trunc(wl.date_updated) between :start_date and :end_date"
+ " and (ic.item_name in ('" + Join(Parameters!list.Value , "', '")" + ') OR"
+ " wl.source_updated = :username OR"
+ " wl.to_container in ('" + Join(Parameters!LPNList.Value , "', '")" + ') OR"
+ " (:list = '_N/A_' and :username is null and :LPNList = '_N/A_')"
+ " )"
+ " order by date_updated desc"
In this case you will need to provide default empty values to your lists. I used 'N/A' in my example.

#query with named #param returning empty result set when using sql IN

Btw this is already working with a jdbc template based solution that I wrote. It's not me wanting to do the rewrite, it is the tec lead's idea. It is giving me a headache.
Lets not get into the discussion on why this is or isn't a good idea, but rather how to make it work.
in my repo
#Repository
interface Foo...extends JpaRepository
this works:
#Query(value = "SELECT t.td, em.ct, j.dsc AS bs, ct.dsc AS ct_name, "
+ "t.tn, et.dsc, f.f_id, f.f_life, f.fl_name, em.f_note "
+ "FROM ext_master em join tax t on em.td = t.td "
+ "join bs j on j.bs = t.bs "
+ "join ex_type et on em.ex_type = et.ex_type "
+ "join ct ct on ct.ct = em.ct "
+ "left join ex_f ef on em.td = ef.td and em.ct = ef.ct "
+ "left join f f on ef.f_id = f.f_id "
+ "WHERE em.ct in ( 'CC' ) "
+ "AND t.state IN ('FF','AK','AL','GA')"
+ "ORDER BY bs, t.tn", nativeQuery = true)
List<Object> getExtensionsByCustTypeAndState(#Param("custTypes") String custTypes, #Param("states") String states);
this doesn't returns empty result set
#Query(value = "SELECT t.td, em.ct, j.dsc AS bs, ct.dsc AS ct_name, "
+ "t.tn, et.dsc, f.f_id, f.f_life, f.fl_name, em.f_note "
+ "FROM extension_master em join tax t on em.td = t.td "
+ "join bs j on j.bs = t.bs "
+ "join exemption_type et on em.ex_type = et.ex_type "
+ "join ct ct on ct.ct = em.ct "
+ "left join ex_f ef on em.td = ef.td and em.ct = ef.ct "
+ "left join f f on ef.f_id = f.f_id "
+ "WHERE em.ct in ( :custTypes ) "
+ "AND t.state IN ('FF', :states)"
+ "ORDER BY bs, t.tn", nativeQuery = true)
List<Object> getExByCustTypeAndState(#Param("custTypes") String custTypes, #Param("states") String states);
both can have one or multiple values, I tried:
with both params like {:states} :#{#states}
with the value inside the param
surrounded by " or by '
passing the whole line in the parameter like "AND t.state IN ('FF','AK','AL','GA')"
passing the 'FF','AK','AL','GA' in the states param and subtituting the in the query with
+ "AND t.state IN ( :states)"
I did write a simple query to make sure I am getting the parameters passed in right. so that's working.
Can anyone write this right, so that the in statements work, or tell me why it is not possible.
Thank you.
You pass all the possible values in one parameter that's why you don't get the results you are expecting.
You have to change the where clause like this:
"WHERE em.ct in ( :custTypes1, :custTypes2, :custTypes3 .... :custTypesN) "
this ended up being the simplest solution
instead of :
"WHERE em.ct in ( :custTypes ) "
+ "AND t.state IN ('FF', :states)"
do:
"WHERE em.ct in :custTypes "
+ "AND t.state IN :states "
and add the FF to the states string on before I call the function.

native query with spring data jpa doesn't return result

Hello I have written the following method in spring data jpa repo:
#RestResource(exported = false)
#Query(
value = "select q.* " +
"from question q " +
"left join question_program qp " +
"on q.question_id = qp.question_id " +
"where " +
"q.difficulty_level_id = ?1 " +
"and " +
"q.paid = false " +
"and " +
"qp.program_id = ?2 " +
"order by random() " +
"limit ?3",
nativeQuery = true
)
List<Question> getFreeRandomQuestions(
#Param("df") Integer df,
#Param("programId") Integer programId,
#Param("qs") Integer qs);
It is returning an empty list whereas when I run the same query in pgadmin I get all the desired rows. It also works in spring data jpa if I remove the join with question_program. What am I doing wrong?
UPDATE:
I have tried select q ... and select * .... Both have the same problem
UPDATE:
I kind of solved this by implementing a service which fetches that data using sessionFactory and raw sql query!.

SQL Inner Join query returns no results

I'm refactoring a Java program written by someone else a couple of years ago, can't get in contact with them to find out anything about the SQL / database, but this query is not working (not returning any results when having two queries separately does). I know it's annoying to ask without more info, but I haven't really got much choice at the moment.
"SELECT " + CLMHDR + ".POLBRC, "
+ CLMHDR + ".POLTYC, " + CLMHDR + ".POLNOC," + CLMHDR + ".CLTKYC, "
+ POLHDR + ".INCPTP FROM "+ CLMHDR +
"INNER JOIN " + POLHDR + " ON " + CLMHDR + ".CLTKYC = " + POLHDR+ ".CLTKYP"
+ " WHERE POLNOC = "+ polnocSearch
+ " AND POLBRC = '" + polbrcSearch + "'"
+ " AND POLTYC = '" + poltycSearch + "'"
+ " AND DATRPC <= " + claimDate
+ " GROUP BY POLBRC, POLTYC, POLNOC, CLTKYC"
The tables CMLHDR and POLHDR do contain the columns it is referencing, and CLTKYC and CLTKYP are keys in each table. Sorry about the horrible names, we're stuck with RPG as well.
Edit:
What does work is this:
"SELECT POLBRC, POLTYC, POLNOC, CLTKYC FROM "+ CLMHDR
+ " WHERE POLNOC = "+ polnocSearch
+ " AND POLBRC = '" + polbrcSeach + "'"
+ " AND POLTYC = '" + poltycSearch + "'"
+ " AND DATRPC <= " + claimDate
+ " GROUP BY POLBRC, POLTYC, POLNOC, CLTKYC"
followed by this:
"SELECT INCPTP, TRMTHP FROM "+ POLHDR + " WHERE POLNOP = "+ polnocSearch
+ " AND POLBRP = '"+ polbrcSearch+ "' AND POLTYP = '"+ poltycSearch + "'"
but I'd really prefer all the data to be returned at once.
There is a space missing between the FROM and the INNER JOIN clause:
FROM "+ CLMHDR +
"INNER JOIN
It is should be this:
FROM "+ CLMHDR +
" INNER JOIN
In addition to the inner join problem, you have an issue with the group by. It should have INCPTP. In any database except for MySQL, this will generate an error.
By the way, it would be easier to answer your question if it included two things:
The database engine you are using
The resulting query string with the values filled in