Re-write the if logic to DECODE statement in Informatica - expression

I have logic which i need to convert it to decode statement
My logic is below :
if emptr =='SBCS':
empcd=empvar
else:
if empcal <> depcal and empid in ('SSC','HSC'):
empcd = (emp_sal/avgsal) * empad
elif empcal <> depcal and empid not in ('SSC','HSC'):
empcd = emp_del
else:
empcd = emp_dev
Tried myself to write the logic in expression
IIF ( emptr ='SBCS' , empvar , IIF(empcal <> depcal,IIF(empcal <> depcal and empid in ('SSC','HSC'),(emp_sal/avgsal) * empad,emp_del),emp_dev))
I have written DECODE logic , but not sure right or wrong
DECODE(TRUE,
empid ='SBCS', empvar,
empcal <> depcal and (empid = 'SSC' or empid = 'HSC'), (emp_sal/avgsal) * empad,
empcal <> depcal and (empid <> 'SSC' or empid <> 'HSC'), emp_del,
emp_dev
)
Feel free to share your logic if the DECODE logic is not right

You can refer to below expression. Pls remove comments (--comments) if needed.
iif (emptr ='SBCS', empvar,
iif( -- first else if part
empcal <> depcal and IN (empid, 'SSC','HSC'), (emp_sal/avgsal) * empad,
iif ( --second elif
empcal <> depcal and NOT IN (empid, 'SSC','HSC') , emp_del,
emp_dev -- last else
)
)
)
I can see your expression and can see some issue with 3rd or condition. in case of NOT IN, or doesnt work. I changed your decode so you can use code below but pls check it before using it.
DECODE(TRUE,
empid ='SBCS', empvar,
empcal <> depcal and (empid = 'SSC' or empid = 'HSC'), (emp_sal/avgsal) * empad,
empcal <> depcal and (empid <> 'SSC' and empid <> 'HSC'), emp_del,
emp_dev
)

I believe I've already answered this exact question there. Was there anything wrong with the below code I provided?
DECODE(TRUE,
empid ='SBCS', v_employee_code_number,
empcal <> depcal and (empid = 'SSC' or empid = 'HSC'), (emp_sal/avgsal) * empad,
empcal <> depcal and empid <> 'SSC' and empid <> 'HSC', emp_del,
emp_dev
)

Related

Select into with substring and orderby

I need to pass a string from a substring of a database column into a variable.
Originally I did this before I realised that this could return more than one row. In the case of this returning more than I row I need to make sure I only return the most recent value (the most recent date).
SELECT SUBSTR (
description
,1
, INSTR (
description
,' ' )
- 1 )
INTO v_value
FROM sdok s
WHERE s.type = 2
AND s.case_no = in_object.case_no;
Which is why I attempted this:
SELECT *
FROM (SELECT SUBSTR (
description
,1
, INSTR (
description
,' ' )
- 1 )
,s.case_no
,s.date
FROM sdok s
WHERE s.type = 2
AND NVL ( s.deleted, 'N' ) <> 'J'
ORDER BY s.date)
WHERE ROWNUM = 1
AND s.case_no = in_object.case_no;
This returns 3 columns of data, which enables me to check I have the right case and date, but I still only really need the value from column 1 (the substring) to pass into my variable. I tried putting INTO after the SUBSTR, but before the call to s.case_no and s.date, but that doesn't work. Yet I need to do the date comparison (to get the most recent date) and get the right case_no, before I can get the first row. I'm guessing there is another way to compare the case_no and order by date, so that I only return the value of the substring?
Help please?
This is how I understood the question:
SELECT x.a_substring
INTO local_variable
FROM (SELECT SUBSTR (description
,1
,INSTR (description, ' ' ) - 1
) a_substring
--
,s.case_no
,s.date
FROM sdok s
WHERE s.type = 2
AND NVL ( s.deleted, 'N' ) <> 'J'
AND s.case_no = 'xxxxxxxxx'
ORDER BY s.date
) x
WHERE ROWNUM = 1
You can do much easier using "first first 1 rows only" or aggregate function max(str)keep(dense_rank first order by s.date):
SELECT
SUBSTR (description
,1
,INSTR (description, ' ' ) - 1
) a_substring INTO local_variable
FROM sdok s
WHERE s.type = 2
AND NVL ( s.deleted, 'N' ) <> 'J'
AND s.case_no = 'xxxxxxxxx'
ORDER BY s.date
fetch first 1 rows only
/
SELECT max(
SUBSTR (description
,1
,INSTR (description, ' ' ) - 1
)
)keep(dense_rank first order by s.date) a_substring
INTO local_variable
FROM sdok s
WHERE s.type = 2
AND NVL ( s.deleted, 'N' ) <> 'J'
AND s.case_no = 'xxxxxxxxx'
/

ORA-01427 Single row subquery return more than one row

I have the below query once I run it, it's exceeded successfully without error, but when I run it inside a procedure, I got the single error.
CREATE OR REPLACE PROCEDURE ABLEA_NEW.AB_VATFILE
IS
fHandle UTL_FILE.FILE_TYPE;
err varchar2(200);
v_str VARCHAR2(4000);
CURSOR VAT1 IS
SELECT (SELECT cif_no
FROM nbfc_customer_m
WHERE customerid = a.bpid) ||
(SELECT EXTRACT_ACCT(HOST_ACCT_INFO, 'SUFFIX')
FROM LEA_AGREEMENT_GROUPGL_MAP A, FA_ACCTCATG_M B
WHERE EXTRACT_ACCT(A.HOST_ACCT_INFO, 'ACCTCATG') = B.ACCTCATG
AND B.GROUPID = 'FA'
AND A.ACTIVE_FLAG = 'Y'
and AGREEMENTID = a.caseid)
"Account No",lpad(a.caseid,6,0) Loan_No
,
(SELECT AGREEMENTNO
FROM lea_agreement_dtl
WHERE AGREEMENTID = a.caseid)
AGREEMENTNO
,
LPAD(A.productid,3,0) Scheme_ID,
(SELECT rpad(schemedesc,35,' ')
FROM lea_scheme_m
WHERE schemeid = a.productid)
SchemeDesc,
to_char(a.advicedate,'ddmmyyyy') advicedate,
it_conv(a.adviceamt) adviceamt,
rpad(a.chargeid,6,' ')chargeid,
(SELECT rpad(chargedesc,35,' ')
FROM nbfc_charges_m
WHERE chargeid = a.chargeid)
"Charge Description",
IT_CONV(a.chargeamt)chargeamt,
(SELECT
decode(count(1),0,'N','Y')
FROM nbfc_pmnt_dtl y
WHERE a.txnadviceid = y.txnadviceid
AND a.status = 'A'
AND y.status IS NULL
--and TRUNC(y.pmntdate) between :p_datefrom and :p_dateto
AND a.tax_applicable = 'Y'
AND a.ptxnadviceid IS NULL)Paid,
LPAD(b.chargeid,6,0)
"VAT ChargeID",
(SELECT RPAD(chargedesc,35,' ')
FROM nbfc_charges_m
WHERE chargeid = b.chargeid)
"VAT Charge Description",
IT_CONV(b.chargeamt)
"VAT Amount"
FROM (SELECT *
FROM nbfc_txn_advice_dtl
WHERE status = 'A' AND tax_applicable = 'Y' AND ptxnadviceid IS NULL)
a,
(SELECT *
FROM nbfc_txn_advice_dtl
WHERE status = 'A' AND ptxnadviceid IS NOT NULL) b
WHERE a.txnadviceid = b.ptxnadviceid;
BEGIN
fHandle := UTL_FILE.FOPEN('UAEDB', 'VAT', 'W');
FOR I IN VAT1
LOOP
v_str:= null;
v_str:= I."Account No"||I.Loan_No||I.AGREEMENTNO || I.Scheme_ID ||I.SchemeDesc|| I.advicedate|| I.adviceamt|| I.chargeid||I."Charge Description"||I.chargeamt||I.Paid||
I."VAT ChargeID" ||I."VAT Charge Description"||I."VAT Amount";
UTL_FILE.PUTF(fHandle,v_str);
UTL_FILE.PUTF(fHandle, '\n');
END LOOP;
UTL_FILE.FCLOSE(fHandle);
END ;
/
How can I solve this?
Note: the query return mor than 10000 record.
comment or un-comment the "(select from )as ColumnAlias" query column one by one, you can find which sub query column return more than one row

Oracle filter results by limit

I am new to Oracle and was hoping someone could help me.
I have this stored procedure:
procedure ListCatalogues(P_CUR out sys_refcursor,
P_CATALOGUENAME varchar2 default '%',
P_LIMIT number,
P_MEMBERS number default -1) is
begin
open P_CUR for
select *
from ( select h.catalogueid id,
h.cataloguename name,
case
when h.uniquecatalogue = 'N'
then 1
else 0
end includeproducts,
case
when h.active = 'Y'
then 1
else 0
end active,
case
when h.ownbrandedlabels = 'Y'
then 1
else 0
end ownlabels,
( select count(*)
from cc_custprofiles t
where t.catalogueid = h.catalogueid
) members
from cc_ob_catalogueheader h
where upper(h.cataloguename) like upper('%'||P_CATALOGUENAME||'%')
and (select count(*) from cc_custprofiles t where t.catalogueid = h.catalogueid) >= P_MEMBERS
order by h.catalogueid
)
where rownum <= P_LIMIT;
end ListCatalogues;
As you can see, it accepts a P_LIMIT parameter which allows for limiting the results returned. This is fine, but I want to expand on it a little.
If the limit is 10, then return 10 rows, but if the limit is 0, return everything. Can someone help me change the query to match my criteria?
I managed this after a bit of looking around:
where rownum <= case when P_LIMIT = 0 then rownum else P_LIMIT end;

How can I join these two select queries into one query?

this is my first time posting, so I am sure I will get a number of things wrong. Do not hesitate to correct me and I will do everything I can to clarify.
In Oracle SQL Developer, I am trying to take two separate SELECT statements and combine them to get one row of results. Unfortunately, because this is sensitive data, I am unable to give any results from the statements individually, but instead, just the SQL statements themselves. I suspect I should be able to join these two on the field "emplid" but just cannot get there. Any help is greatly appreciated! Here is the code below, please mind the syntax :)
1st Select statement is giving me a list of people that were paid in 2017:
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
And 2nd Select statement would be a list of the deductions taken for the employees that were identified in the first statement:
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
Ideally, what I'd like to do is put in a value in place of 'XXXXXX' and get one row of data with the two combined statements.
Thanks everyone!
To do this, we stick each SELECT statement into a subquery and give that subquery an alias to refer to in the main queries select statement:
SELECT t1.*, t2.*
FROM
(
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
) t1
INNER JOIN
(
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
) t2 ON
t1.empid = t2.empid
We just treat each derived table/subquery as it's own table and join them on empid. You can tweak the SELECT statement at the top as needed.
This is similar to creating a view for both sql statements and then referencing the views in a third sql statement.
An alternative way of doing this is to use CTE (Common Table Expressions) to house the separate sql. There's no performance advantage here, but you might find it easier to read.
WITH t1 as
(
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
),
t2 AS
(
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
)
SELECT t1.*, t2.*
FROM t1 INNER JOIN t2 ON
t1.empid = t2.empid
Basically you do something like
select blah, blah.. (your second query )
AND G.EMPLID IN ( SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
)
So basically I have used your first query in you second query. I removed the DISTINCT, as its not needed.
I hope that makes sense.

Gettin error ORA-01732: data manipulation operation not legal on this view

Hi Gurus I am getting the error ORA-01732: data manipulation operation not legal on this view
when executing the below query
UPDATE (SELECT CR.AMOUNT AS AMOUNT,
CASE
WHEN MRG.AMOUNT_USD=0
THEN CR.AMOUNT
ELSE MRG.AMOUNT_USD
END AS AMOUNT_BILAT,
CR.ISUPDATED
FROM CRS_TT_BILAT_EXCL_MERGE1 MRG,CRS_T_CURRENT_RATES1 CR
WHERE SUBSTR(CR.DNIS_CD,1,3)=MRG.DNIS_CD
AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID
AND CR.ISUPDATED <> 'Y'
AND ROWNUM = 1)
SET AMOUNT = AMOUNT_BILAT;
CR.ISUPDATED = 'Y';
I have simplified the above code from the below query
UPDATE CRS_T_CURRENT_RATES1 CR
SET CR.AMOUNT =
(SELECT
CASE
WHEN MRG.AMOUNT_USD=0
THEN CR.AMOUNT
ELSE MRG.AMOUNT_USD
END
FROM CRS_TT_BILAT_EXCL_MERGE1 MRG
WHERE SUBSTR(CR.DNIS_CD,1,3)=MRG.DNIS_CD
AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID
AND ROWNUM = 1),
CR.ISUPDATED = 'Y'
WHERE EXISTS
(SELECT 1 FROM CRS_TT_BILAT_EXCL_MERGE1 MRG WHERE MRG.DNIS_CD = SUBSTR(CR.DNIS_CD, 1,3) AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID )
AND
CR.ISUPDATED <> 'Y';
I was trying to optimize the 2nd query, since the second query uses two selects i was trying to replace that with a single query. Can any one please help me on this?
MERGE statement with selecting 1st row for each (AMOUNT_USD, DNIS_CD, PRODUCT_CUST_ID) - ROWNUM=1 condition from your query:
MERGE INTO CRS_T_CURRENT_RATES1 CR
USING (SELECT * FROM (
SELECT AMOUNT_USD,
DNIS_CD,
PRODUCT_CUST_ID
ROW_NUMBER() OVER (PARTITION BY AMOUNT_USD, DNIS_CD, PRODUCT_CUST_ID ORDER BY 1) AS ORD_NO
FROM CRS_TT_BILAT_EXCL_MERGE1
) WHERE ORD_NO = 1
) MGR
ON CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID AND
SUBSTR(CR.DNIS_CD,1,3)=MRG.DNIS_CD
WHEN MATCHED THEN
UPDATE SET CR.AMOUNT = (CASE
WHEN MRG.AMOUNT_USD=0 THEN CR.AMOUNT
ELSE MRG.AMOUNT_USD
END),
ISUPDATED = 'Y'
WHERE ISUPDATED <> 'Y';
UPDATE: Using MERGE and ROWNUM won't work.
MERGE can help you avoid repeating SQL:
MERGE INTO CRS_T_CURRENT_RATES1 CR
USING
(
SELECT AMOUNT_USD, DNIS_CD, PRODUCT_CUST_ID
FROM CRS_TT_BILAT_EXCL_MERGE1
) MRG
ON
(
SUBSTR(CR.DNIS_CD,1,3) = MRG.DNIS_CD
AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID
AND ROWNUM = 1
)
WHEN MATCHED THEN UPDATE SET
CR.ISUPDATED = 'Y',
CR.AMOUNT = CASE WHEN MRG.AMOUNT_USD=0 THEN CR.AMOUNT ELSE MRG.AMOUNT_USD END
Update
ROWNUM in the ON clause works on the updated table, not the data in the USING clause. The example below starts with two identical rows and only one gets updated:
create table test1(a number, b number);
insert into test1 values(1, 1);
insert into test1 values(1, 1);
merge into test1
using
(
select 1 a from dual
) test2
on (test1.a = test2.a and rownum = 1)
when matched then update set b = 0;
select * from test1;
A B
- -
1 0
1 1

Resources