How do i get this CASE statement right in PLSQL? - oracle

I'm getting ORA- 00936 missing expression error near > symbol while trying to run this request :
SELECT contract_ref_no,
component
FROM some_table
WHERE Contract_ref_no = '123'
AND component = 'ABC'
AND end_date
(CASE WHEN NVL(l_neg_esn_allowed,'N') = 'N'
THEN
> greatest(nvl(l_conv_eff_date, l_contract_vdate),
l_contract_vdate)
ELSE
>=
greatest(nvl(l_conv_eff_date, l_contract_vdate),
l_contract_vdate)
END)
How can I fix it?

With a bit reformulation based on the rules of Aristoteles you may write
you allways want the end_date is greather than your greatest expression
OR
in the else case NVL(l_neg_esn_allowed,'N') != 'N' thay may be equal
Predicate
...
AND (
end_date > greatest(nvl(l_conv_eff_date, l_contract_vdate), l_contract_vdate)
OR
NVL(l_neg_esn_allowed,'N') != 'N' and end_date = greatest(nvl(l_conv_eff_date, l_contract_vdate), l_contract_vdate)
)
which is the same as the predicate below that more resembles your original intention
....
AND (
NVL(l_neg_esn_allowed,'N') = 'N' AND end_date > greatest(nvl(l_conv_eff_date, l_contract_vdate),l_contract_vdate)
OR
NVL(l_neg_esn_allowed,'N') != 'N' AND end_date >= greatest(nvl(l_conv_eff_date, l_contract_vdate),l_contract_vdate)
)

You can change your case statement to -
SELECT contract_ref_no,
component
FROM some_table
WHERE Contract_ref_no = '123'
AND component = 'ABC'
AND CASE WHEN NVL(l_neg_esn_allowed,'N') = 'N'
AND end_date > greatest(nvl(l_conv_eff_date, l_contract_vdate),
l_contract_vdate) THEN
1
WHEN end_date >= greatest(nvl(l_conv_eff_date, l_contract_vdate),
l_contract_vdate) THEN
1
END = 1;

The SQL query that you write have syntax error.
The THEN > something can't work : Superior to what ? Same with the >= after, superior or equals to what ?
So, you should have something like column > value, such as you will have column = value or column LIKE 'my val'.
Finally, I suggest you to use this code:
SELECT contract_ref_no,
component
FROM some_table
WHERE Contract_ref_no = '123'
AND component = 'ABC'
AND end_date
(CASE WHEN NVL(l_neg_esn_allowed,'N') = 'N'
THEN some_date > greatest(nvl(l_conv_eff_date, l_contract_vdate),
l_contract_vdate)
ELSE some_date >= greatest(nvl(l_conv_eff_date, l_contract_vdate),
l_contract_vdate)
END)

Related

Missing keyword error in Case when in oracle

My select query before changes was:
select * from abc
WHERE
CASE WHEN NVL(gr.Rgid,a.pc) = 'CRA' THEN
CASE WHEN NVL(TRUNC(a.DATEOFSFROM),TO_DATE('99991231','YYYYMMDD')) >= TO_DATE('20170101','YYYYMMDD') THEN 'Y' ELSE 'N' END
When gr.Rgid='021SHOP' THEN
CASE WHEN TRUNC(a.datep) <= to_date('20190630', 'YYYYMMDD') then 'Y' ELSE 'N' end
ELSE 'Y' END = 'Y'
I need new case when statement,so I added:
select * from abc
WHERE
CASE WHEN NVL(gr.Rgid,a.pc) = 'CRA' THEN
CASE WHEN NVL(TRUNC(a.DATEOFSFROM),TO_DATE('99991231','YYYYMMDD')) >= TO_DATE('20170101','YYYYMMDD') THEN 'Y' ELSE 'N' END
When gr.Rgid='021SHOP' THEN
CASE WHEN TRUNC(a.datep) <= to_date('20190630', 'YYYYMMDD') then 'Y' ELSE 'N' end
ELSE 'Y' END = 'Y'
CASE WHEN NVL(gr.Rgid,a.pc) IN ('01FLW','002FE') then
a.datep <=to_date('20180131', 'YYYYMMDD') END;
I added these statement from my side
CASE WHEN NVL(gr.Rgid,a.pc) IN ('01FLW','002FE') then
a.datep <=to_date('20180131', 'YYYYMMDD') END;
But I am getting error:ORA-00905:missing keyword error. I searched these similar question but I only see is case when used is being wrong.But from my analysis,the case when I am using in right.
You didn't say what exactly should be the outcome so I guessed. Note comments within code, which contains new CASE:
SELECT *
FROM abc
WHERE CASE
WHEN NVL (gr.Rgid, a.pc) = 'CRA'
THEN
CASE
WHEN NVL (TRUNC (a.DATEOFSFROM),
TO_DATE ('99991231', 'YYYYMMDD')) >=
TO_DATE ('20170101', 'YYYYMMDD')
THEN
'Y'
ELSE
'N'
END
WHEN gr.Rgid = '021SHOP'
THEN
CASE
WHEN TRUNC (a.datep) <= TO_DATE ('20190630', 'YYYYMMDD')
THEN
'Y'
ELSE
'N'
END
-- your new WHEN begins here ...
WHEN NVL (gr.Rgid, a.pc) IN ('01FLW', '002FE')
THEN
CASE
WHEN a.datep <= TO_DATE ('20180131', 'YYYYMMDD')
THEN 'Y'
ELSE 'N'
END
-- ... and ends here
ELSE
'Y'
END =
'Y'
Your query:
select * from abc
WHERE
CASE WHEN NVL(gr.Rgid,a.pc) = 'CRA' THEN
CASE WHEN NVL(TRUNC(a.DATEOFSFROM),TO_DATE('99991231','YYYYMMDD')) >= TO_DATE('20170101','YYYYMMDD') THEN 'Y' ELSE 'N' END
When gr.Rgid='021SHOP' THEN
CASE WHEN TRUNC(a.datep) <= to_date('20190630', 'YYYYMMDD') then 'Y' ELSE 'N' end
ELSE 'Y' END = 'Y'
that's all ok.
When adding CASE WHEN NVL(gr.Rgid,a.pc) IN ('01FLW','002FE') then a.datep <=to_date('20180131', 'YYYYMMDD') END to the end you're screwing up the syntax.
Syntax: where a = b or c = d.
You wrote where a = b and then added c so it becomes where a = b c.
Add your new line with a AND or OR and get a value to compare it to, like
SELECT * FROM ABC
WHERE
CASE WHEN NVL(gr.Rgid,a.pc) = 'CRA' THEN
...
ELSE 'Y' END = 'Y'
-- new here
AND CASE WHEN NVL(gr.Rgid,a.pc) IN ('01FLW','002FE') AND a.datep <=to_date('20180131', 'YYYYMMDD')
then 'true'
ELSE 'false'
END = 'true';
I also transformed your case statement to a equation like a = b by moving your condition into the WHEN-Block and then comparing if it's the first when block or not by ... END = 'true'.
You cannot add where statements within a case expression like you did.
Please note that I wrote this without actual verification, so syntac errors may still occur.

Oracle store procedure to retrieve dates ny passing column name as parameter

The below procedure returns thousands of lines by passing start date and end date. Added to that i need to add one parameter which should apply the start date and end date on different columns such as created date, planned date and end date which are available in result set.
For instance if i pass the value as (created date,'31/10/2020 00:00:00','01/11/2020 00:00:00'), the filter should be applied on created date column, if i pass (end,'31/10/2020 00:00:00','01/11/2020 00:00:00'), the filter should be applied on end date column.
How can i achieve this ?
create or replace PROCEDURE CVP_TEST(STARTDATE VARCHAR, ENDDATE VARCHAR) AS
st_dt TIMESTAMP := TO_TIMESTAMP(STARTDATE, 'dd/mm/yyyy hh24:mi:ss');
end_dt TIMESTAMP := TO_TIMESTAMP(ENDDATE, 'dd/mm/yyyy hh24:mi:ss');
cursor cur1(start_time timestamp, end_time timestamp)
is
SELECT
A.LGST_GRP_CD ,
(case when A.FRST_SHPG_LOC_CD like 'D%' then A.FRST_SHPG_LOC_CD
when (A.FRST_SHPG_LOC_CD not like 'D%' and A.DMCL_CD is not null and length(dmcl_t.shpgloc_cd) <= 4) then dmcl_t.shpgloc_cd
--when (A.FRST_SHPG_LOC_CD not like 'D%' and A.DMCL_CD is null and length(dom_carrier.shpgloc_cd) <= 4) then dom_carrier.shpgloc_cd
else A.FRST_SHPG_LOC_CD end) AS Dispatch_DC,
--ba_tmextra.FUN_GET_INT_DC(A.LD_LEG_ID) AS INT_DC,
'XXX' AS INT_DC,
A.CUR_OPTLSTAT_ID,
--V.CUR_STAT_ID,
A.TRIP_ID AS TRIP_ID,
A.LD_LEG_ID AS LOAD_ID,
A.CARR_CD AS CARRIER_ID,
A.SRVC_CD AS SERVICE_ID,
A.EQMT_TYP AS EQMT_TYP,
A.STRD_DTT AS START_DATE,
A.END_DTT AS END_DTT,
A.CRTD_DTT AS CRTD_DTT,
A.TRCTR_NUM as TRCTR_NUM,
A.DRVR as DRVR,
A.TRLR_NUM,
A.FRST_SHPG_LOC_CD,
A.LAST_SHPG_LOC_CD,
A.NUM_STOP as NUM_STOP,
--BA_TMEXTRA.FUN_GET_STOP_LOC(A.LD_LEG_ID, 0) STOP_LIST,
'XXX' AS STOP_LIST,
LD_MMO.PRTB_CTNT AS LD_COMMENTS,
A.MILE_DIST AS MILE_DIST,
A.TOT_SCLD_WGT AS TOTAL_WEIGHT,
A.ELPD_HRS,
CM.chrg_extl_code2 as chrg_extl_code2,
(case when CM.chrg_extl_code2 = 'HAUL' then C.CHRG_CD else null end) as Haul_Charge_ID,
(case when CM.chrg_extl_code2 = 'HAUL' then C.CHGD_UNIT_RATE else null end) as Planned_Rate,
(case when CM.chrg_extl_code2 = 'FUEL' then C.CHGD_UNIT_RATE else null end) as Fuel_Planned_Rate,
(case when CM.chrg_extl_code2 = 'FUEL' then C.CHRG_CD else null end) as Fuel_Surcharge_Type_ID,
(case when CM.chrg_extl_code2 = 'STOP' then C.CHRG_CD else null end) as Stop_Off_Charge_ID,
--C.CHRG_CD AS CHRG_CD,
--C.CHGD_UNIT_RATE AS PLANNED_RATE,
NVL(C.MNLY_OVRD_DLR,0) as CHRG_GRP_AMT
FROM JDATM_PROD.LD_LEG_T A, JDATM_PROD.CHRG_DETL_T C, JDATM_PROD.IA_DIST_MSTRCHRG CM,
JDATM_PROD.DMCL_T,
--DMCL_T DOM_CARRIER,
--VCHR_AP_T V,
JDATM_PROD.MMO_T LD_MMO
WHERE 1=1
AND A.LD_LEG_ID = C.LD_LEG_ID
AND C.CHRG_CD = CM.CHRG_CODE
AND C.CHRGDETL_TYP_ENU = 1
AND C.CHRG_LVL_ENU != 7
AND A.DMCL_CD=DMCL_T.DMCL_CD(+)
--AND DOM_CARRIER.CARR_CD(+)=A.CARR_CD
--AND V.VCHR_NUM (+) = C.VCHR_NUM_AP
--AND V.CUR_STAT_ID (+) != 825
and A.mmo_id = ld_mmo.mmo_id (+)
AND A.TRIP_ID IS NULL
--AND A.LD_LEG_ID = 1001038103
AND A.RATG_VLID_YN = 'T'
AND A.STRD_DTT BETWEEN start_time and end_time;
read_value cur1%ROWTYPE;
BEGIN
--dbms_output.put_line('Accepted:' || STARTDATE || ', ' || ENDDATE);
--dbms_output.put_line('Assigned:' || st_dt || ', ' || end_dt);
END;
You can use the OR condition as follows:
AND (
(P_IN_COLUMN_NAME = 'created date' AND A.CREATED_DTT BETWEEN start_time and end_time)
OR
(P_IN_COLUMN_NAME = 'planned date' AND A.PLANNED_DTT BETWEEN start_time and end_time )
)

Oracle SQL: Return a set without duplicates

Using the following query is working for me except that I need to only return one result for each TPHONE.ID.
What I'm trying to accomplish is to check two tables for three date fields (two in the TPHONE table and one in the TPHONEREQUEST table and return the TPHONE.ID of any place where I find dates within a particular range. However, if more than one entry in either table has one or more of the dates within the date range I'd still only want to return the TPHONE.ID once.
SELECT
TPHONE.ID,
TPHONE.LOCATIONID,
TPHONE.DLASTCHANGED,
TPHONE.D02,
TPHONEREQUEST.D03
FROM
TPHONE, TPHONEREQUEST
WHERE
TPHONE.ID = TPHONEREQUEST.DEVICEID
AND TPHONE.ID IN
(
SELECT
TPHONE.ID
FROM
TPHONE
WHERE
TPHONE.DLASTCHANGED >= '7/1/2019' AND TPHONE.DLASTCHANGED < '10/1/2019'
OR TPHONE.D02 >= '7/1/2019' AND TPHONE.D02 < '10/1/2019'
OR TPHONEREQUEST.D03 >= '7/1/2019' AND TPHONEREQUEST.D03 < '10/1/2019'
)
ORDER BY
TPHONE.LOCATIONID, TPHONE.ID
You can use aggregation and filter with a HAVING clause:
SELECT p.ID,
FROM
TPHONE p
INNER JOIN TPHONEREQUEST t ON p.ID = r.DEVICEID
GROUP BY p.ID
HAVING
MAX(
CASE WHEN
(
p.DLASTCHANGED >= TO_DATE('07/01/2019', 'DD/MM/YYYY')
AND p.DLASTCHANGED < TO_DATE('10/1/2019', 'DD/MM/YYYY')
) OR (
p.D02 >= TO_DATE('07/01/2019', 'DD/MM/YYYY')
AND p.D02 < TO_DATE('10/1/2019', 'DD/MM/YYYY')
) OR (
r.D03 >= TO_DATE('07/01/2019', 'DD/MM/YYYY')
AND r.D03 < TO_DATE('10/1/2019', 'DD/MM/YYYY')
)
THEN 1
END
) = 1
Notes:
this returns only TPHONE.ID, since this seems to be what you are looking for; if you want more columns, then you can add them to the SELECT clause and to the GROUP BY clause (beware that this might change the grouping condition though, if these columns are not functionnaly dependant on TPHONE.ID)
I used table aliases to shorten the query
I used TO_DATE() to generate proper dates instead of relying on the default format of the database (which may change across databses and sessions). There is an assumption here that the format of your dates is DD/MM/YYYY (it could also be MM/DD/YYYY)
You could use ROW_NUMBER to enumerate the rows with the same ID and then select only the first instance:
SELECT TPHONE.ID,
TPHONE.LOCATIONID,
TPHONE.DLASTCHANGED,
TPHONE.D02,
TPHONEREQUEST.D03
FROM (
SELECT TPHONE.ID,
TPHONE.LOCATIONID,
TPHONE.DLASTCHANGED,
TPHONE.D02,
TPHONEREQUEST.D03,
ROW_NUMBER() over (PARTITION BY TPHONE.ID ORDER BY TPHONE.ID) as RN
FROM TPHONE,
TPHONEREQUEST
WHERE TPHONE.ID = TPHONEREQUEST.DEVICEID
AND TPHONE.ID IN
(
SELECT TPHONE.ID
FROM TPHONE
WHERE TPHONE.DLASTCHANGED >= '7/1/2019' AND TPHONE.DLASTCHANGED < '10/1/2019'
OR TPHONE.D02 >= '7/1/2019' AND TPHONE.D02 < '10/1/2019'
OR TPHONEREQUEST.D03 >= '7/1/2019' AND TPHONEREQUEST.D03 < '10/1/2019'
)
ORDER BY TPHONE.LOCATIONID, TPHONE.ID
)
WHERE RN = 1

Plsql Program using control statements

I have a table like "Emp_Info", For the below output i have used "two" SELECT Statements, I want work that using ONE SELECT STATEMENT.
select count(*) into cnt
from emp_info t
where upper(trim(t.email)) = upper(trim(field1value))
and t.company_id = companyId;
select
(case when cnt1 > 0 then 'YES' else 'NO' end) into val_acc
from (
select count(*) cnt1 from
emp_info t
where upper(trim(t.email)) = upper(trim(field1value))
and (t.account_expiry_dt is null or t.account_expiry_dt >= sysdate)
and t.company_id = companyId
);
if cnt = 0 then
raise_application_error(-20002, 'User does not exist');
elsif cnt > 1 then
raise_application_error(-20003, 'Duplicate records found');
elsif val_acc = 'NO' then
raise_application_error(-20004, 'Account has expired');
else
/* some logic */
end if;
end;
may be this help you
select count(*),
CASE WHEN
sum( CASE when t.account_expiry_dt is null or t.account_expiry_dt >= sysdate then 1 else 0 end) > 0 then 'YES'
else 'NO'
END
into cnt, val_acc
from emp_info t
where upper(trim(t.email)) = upper(trim(field1value))
and t.company_id = companyId;
simple demo:
with emp_info(login,username) as (select 'test', 'test' from dual union
select 'TEst', 'TEst' from dual )
select count(*) emp_count,
CASE when sum( CASE WHEN login like '%st%' then 1 else 0 end) > 0 then 'Y' else 'N' end emp_flag,
sum( CASE WHEN login like '%st%' then 1 else 0 end) emp_flag_count,
CASE when sum( CASE WHEN login like '%te%' then 1 else 0 end) > 0 then 'Y' else 'N' end emp_flag1,
sum( CASE WHEN login like '%te%' then 1 else 0 end) emp_flag_count1,
CASE when sum( CASE WHEN login like '%TE%' then 1 else 0 end) > 0 then 'Y' else 'N' end emp_flag2,
sum( CASE WHEN login like '%TE%' then 1 else 0 end) emp_flag_count2
from emp_info
answer if it helped you

ThinkingSphinx with_all OR query

I'm trying to return results who's start_date or end_date fall within a date range. I'm using with_all in my TS query like such:
range = (start_date..end_date)
with_all = { start_date: [range], end_date: [range] }
However, this does not work because I believe this will require both the start_date and end_date to fall within the range.
What do I need to do so that it will return results if either the start_date or end_date fall within the range?
After much non Rock related head banging I found a working solution.
srange = date_range[:start].to_datetime.utc.beginning_of_day.to_i
erange = date_range[:end].to_datetime.utc.end_of_day.to_i
# * full range falls within start_date & end_date
# * start_date & end_date is within the full range
# * end range is within start_date & end_date
# * start range is within start_date & end_date
sphinx_select = "
*, (IF(
#{srange} >= start_date AND
#{srange} <= end_date AND
#{erange} >= start_date AND
#{erange} <= end_date, 1, 0) +
IF(
start_date >= #{srange} AND
start_date <= #{erange} AND
end_date >= #{srange} AND
end_date <= #{erange}, 1, 0) +
IF(
#{srange} <= start_date AND
#{srange} <= end_date AND
#{erange} >= start_date AND
#{erange} <= end_date, 1, 0) +
IF(
#{srange} >= start_date AND
#{srange} <= end_date AND
#{erange} >= start_date AND
#{erange} >= end_date, 1, 0)) as in_date_range"
MyModel.search('',
select: select,
where: {"in_date_range" => [1,2,3,4]})

Resources