jpa query with case condition in criteria - sql

I have one mysql query like below where I'm using conditional parameter in where clause. How can I rewrite the same in JPA?
SELECT * FROM notification n where if (n.feature_details_id=16, category_id IN (SELECT r.id FROM procurement_category r where r.spendpool_id IN (SELECT spendpool_id FROM procurement_category p where p.id IN (1,4))),category_id IN (4)) and (recipient =76 or n.recipient_type = 'ALL' and n.id NOT IN (select ns.notification_id from notification_statistics ns where ns.user_id =76 and ns.status = 'DISMISSED') and n.sender != 76);
I've tried this. It only works when passing single value to param categoryIds.
#Query("select n from Notification n "
+ "where (n.category.id IN(case when n.featureDetails.id=2 then(SELECT r.id FROM ProcurementCategory r where r.spendpoolId.id IN "
+ "(SELECT p.spendpoolId.id FROM ProcurementCategory p where p.id IN (:categoryIds))) "
+ "else (:categoryIds) end )) "
+ "and n.recipient =:recipient "
+ "or n.recipientType = 'ALL' "
+ "and n.category.id IN (SELECT r.id FROM ProcurementCategory r where r.spendpoolId.id IN "
+ "(SELECT p.spendpoolId.id FROM ProcurementCategory p where p.id IN (:categoryIds))) "
+ "and n.id NOT IN (select ns.notification.id from NotificationStatistics ns where ns.user.id =:recipient and ns.status = 'DISMISSED') "
+ "and n.sender != :recipient " )
If passing multiple values it gives error like
05-11-2016 09:58:32.153 [http-nio-8080-exec-3] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - Operand should contain 1 column(s)
05-11-2016 09:58:32.154 [http-nio-8080-exec-3] DEBUG c.b.i.aop.logging.LoggingAspect - Enter: com.beroe.insync2.web.rest.errors.ExceptionTranslator.dataIntegrityViolationException() with argument[s]

Related

Postgres Left Join ignores row if ManyToOne property is null

In Spring Boot i have the following query in a PostgreSQL database, to get data from ConfigElement table and set them to the new one ConfigurationReview table. It works properly as expected:
#Query(
"SELECT new xx.xx.xx.dao.ConfigurationReview(r.id, MAX(ce.id) AS configElementId,"
+ " r.checkMethod, r.targetDate, r.endDate, r.sessionDate, SUM(CASE WHEN i.criticality ="
+ " 0 AND i.relation = 0 THEN 1 ELSE 0 END) AS majorFindings, SUM(CASE WHEN i.criticality"
+ " = 1 AND i.relation = 0 THEN 1 ELSE 0 END) AS minorFindings, r.state) FROM"
+ " ConfigElement ce "
+ "LEFT JOIN ce.reviews r ON r.configElement.id = ce.id "
+ "LEFT JOIN r.criteria cr ON cr.review.id = r.id "
+ "LEFT JOIN cr.issues i ON i.criterion.id = cr.id "
+ "WHERE ce.id = :configurationId AND r.id IS NOT NULL GROUP BY r.id")
Page<ConfigurationReview> findConfigurationReviews(
#Param("configurationId") Long configurationId, Pageable pageable);
There was a need to add another property (r.milestone) with a ManyToOne relation, so i added it to the query:
#Query(
"SELECT new xx.xx.xx.dao.ConfigurationReview(r.id, MAX(ce.id) AS configElementId,"
+ " r.checkMethod, r.targetDate, r.endDate, r.sessionDate, SUM(CASE WHEN i.criticality ="
+ " 0 AND i.relation = 0 THEN 1 ELSE 0 END) AS majorFindings, SUM(CASE WHEN i.criticality"
+ " = 1 AND i.relation = 0 THEN 1 ELSE 0 END) AS minorFindings, r.state, r.milestone) FROM"
+ " ConfigElement ce "
+ "LEFT JOIN ce.reviews r ON r.configElement.id = ce.id "
+ "LEFT JOIN r.criteria cr ON cr.review.id = r.id "
+ "LEFT JOIN cr.issues i ON i.criterion.id = cr.id "
+ "WHERE ce.id = :configurationId AND r.id IS NOT NULL GROUP BY r.id")
Page<ConfigurationReview> findConfigurationReviews(
#Param("configurationId") Long configurationId, Pageable pageable);
Here is the milestone entry in ConfigurationReview dao:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(foreignKey = #ForeignKey(name = "fk_review_milestones_on_milestone_id"))
private Milestone milestone;
With the above changes, it works properly if r.milestone is not null. But when the r.milestone is null, the complete row is ignored in left join.
As a result, if I have 2 r.milestones with data and 2 r.milestones without, the above query returns only two entries instead of four.
The problem appears only if r.milestone is null (because of the ManyToOne relation?). If another property is null, the row is returned properly.
Any idea how can I fix this?

"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.

Hibernate Query doesn't work as expected

Hi i have the following Query:
String hql = "UPDATE Raumreservierung as rr " +
"set VON = :begin " +
"where VON = :Von " +
"and Raum_ID IN (SELECT r.ID FROM Raum r " +
"inner join r.Panel as pl with pl.ID = " + clientId + "";
IQuery query = CurrentSession.CreateQuery(hql);
query.SetParameter("begin", DateTime.Now);
query.SetParameter("Von", v.Von);
int result = query.ExecuteUpdate();
The Query do an Update on "VON". That works fine, but the rest of the Query is not working. It seems that the rest of the query is not working. But did not get any Error.
With the rest of the Query i mean the following part of the query:
"and Raum_ID IN (SELECT r.ID FROM Raum r " +
"inner join r.Panel as pl with pl.ID = " + clientId + "";
Because it should happen only a Update on the column "VON" for example when "clientId" is "AT2"
But that part is not working. Because the update happens also on other clientId.
You forgot to close your parentheses.
(Also, you should use a parameter for clientId too)

Assignment error is thrown in the query

I have a query like this....
selectLeaveDetails =
"SELECT UL.[PK_ID],UD.FIRST_NAME + ' ' + UD.LAST_NAME AS REQUESTBY," +
"UL.[DATE_FROM] AS FROMDATE,UL.[DATE_TO] AS TODATE," +
"UL.LEAVE_REQUEST_ON AS REQUESTON," +
"REPLACE(UL.LEAVE_REQUEST_NOTES, '\n', '<br />') AS REQUESTNOTES," +
"STATUS=CASE " +
" WHEN UL.[LEAVE_STATUS] = '1' THEN 'ACTIVE' " +
" WHEN UL.[LEAVE_STATUS] = '-1' THEN 'CANCELLED' " +
" WHEN UL.[LEAVE_STATUS] = '2' THEN 'REPLACED' END," +
"UL.LEAVE_RESPONSE_ON AS RESPONSEON," +
"ULL.FIRST_NAME + ' ' + ULL.LAST_NAME AS RESPONSEBY," +
"UL.[LEAVE_RESPONSE_NOTES] AS RESPONSENOTES,UL.FK_LEAVE_REQUESTER " +
"FROM (M_USER_LEAVES UL " +
"INNER JOIN M_LEADERLED MLL ON MLL.LED_ID = MUD.PK_ID WHERE MLL.LEADER_ID = '" + Session["UserID"].ToString() ****" +****
"LEFT JOIN M_USER_DETAILS UD ON UD.PK_ID = UL.FK_LEAVE_REQUESTER) " +
"LEFT JOIN M_USER_DETAILS ULL ON ULL.PK_ID = UL.FK_LEAVE_RESPONSE_BY " +
" WHERE UL.DATE_FROM BETWEEN '01/01/" + cmbYearList.SelectedItem.Text + "' AND '12/31/" + cmbYearList.SelectedItem.Text + "'" +
" AND UD.ACTIVE=1";
In the cmbYearList.SelectedItem.Text + "' AND '12/31/" + cmbYearList.SelectedItem.Text + "'" query...only assignment,increment,decrement error is thrown
Can anyone help me?
Your FROM clause is somehow pretty mangled up:
FROM (M_USER_LEAVES UL
INNER JOIN M_LEADERLED MLL ON MLL.LED_ID = MUD.PK_ID
WHERE MLL.LEADER_ID = 'XXXX"
LEFT JOIN M_USER_DETAILS UD ON UD.PK_ID = UL.FK_LEAVE_REQUESTER)
You have an INNER JOIN, then a WHERE clause, followed by a LEFT JOIN .... this seems pretty odd..... what exactly are you trying to do here?? Why do you need to put this into a subquery - can't you just INNER JOIN and LEFT JOIN those tables into a single statement and define the necessary WHERE constraints?
Also, your WHERE clause in here gets an opening single quote and a closing double quote - that won't work ......
WHERE MLL.LEADER_ID = 'XXXX"
*** ***
You need to get your SQL query working in SQL Server Management Studio first - then transfer it into your C# code.