Plsql Program using control statements - oracle

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

Related

Count and Sum inside a select with multiple sums and counts

I'm using sub-query factoring and I have a query that returns invoice lines, and in the end I have this final sub-query:
I've already tried Partition but without success
SELECT
COUNT(CASE WHEN PC <> 0 THEN 1 END) AS A_LINECOUNT,
SUM(CASE WHEN PC > 0 THEN NR ELSE 0 END) AS B_PRODUCTCOUNT,
COUNT(CASE WHEN ALLOW_PAY = 1 THEN 1 END) AS C_INVOICECOUNT, --- ERROR
SUM(CASE WHEN ALLOW_PAY = 1 THEN MISSING_VALUE ELSE 0 END) AS D_INVOICETOTAL, --- ERROR
COUNT(CASE WHEN IS_NON_LIQUIDABLE_PRODUCT = 1 THEN 1 END) AS E_CONDITIONCOUNT,
COUNT(CASE WHEN IS_LIQUIDABLE_PRODUCT = 1 THEN 1 END) AS F_CONDITIONCOUNT
FROM MAIN_Q
The calculation of C_INVOICECOUNT and D_INVOICETOTAL is not correct because their values are repeated within each line of the invoice. Please consider that um MAIN_Q i also have a document_id where i can group by.
thanks
Maybe I understood correctly, maybe not, but this is too long for comment. If yes, C_INVOICECOUNT can be count as:
count(distinct case when allow_pay = 1 then document_id end)
But the problem is with D_INVOICETOTAL. You have repeated values for each invoice here and details which do not repeat. If so, add row numbering to your query:
select main_q.*, row_number() over (partition by document_id) rn from main_q
and then in problematic places use rn = 1:
select ...
count(case when rn = 1 and allow_pay = 1 then 1 end),
sum(case when rn = 1 and allow_pay = 1 then missing_value else 0 end)
...
from (select main_q.*, row_number() over (partition by document_id) rn from main_q)
Only first rows for each invoice will be analysed. Of course you can add row_number in earlier step.

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;

Oracle sqlplus query

I am getting "Invalid Number"
Can anyone please guide me what I am doing wrong here ???
select TO_CHAR(a.START_TIME,'YY-MON-DD HH24') as START_TIME,
count(*) AS NbOperations,
SUM(CASE WHEN OPERATION_RESULT=0 THEN 1 ELSE 0 END) AS Success,
SUM(CASE WHEN OPERATION_RESULT=200 THEN 1 ELSE 0 END) AS Cancel,
SUM(CASE WHEN OPERATION_RESULT=203 THEN 1 ELSE 0 END) AS AppletInternalError,
SUM(CASE WHEN OPERATION_RESULT=406 THEN 1 ELSE 0 END) AS TimeoutWaitForCard,
SUM(CASE WHEN OPERATION_RESULT=413 THEN 1 ELSE 0 END) AS BillingError,
SUM(CASE WHEN OPERATION_RESULT=1000 THEN 1 ELSE 0 END) AS ABANDONNED,
SUM(CASE WHEN OPERATION_RESULT=1004 THEN 1 ELSE 0 END) AS ABANDON_FOR_NEW_OPERATION,
SUM(CASE WHEN OPERATION_RESULT NOT IN (0,200,203,406,413,1000,1004) THEN 1 ELSE 0 END) AS NbOthers
from MyTable1 a,
MyTable2 b
where OPERATION_TYPE in (2,3,4,5)
and a.OPERATION_TYPE=b.OPERATION_ID
and a.START_TIME >= to_timestamp('&1', 'YYYY-MM')
and a.START_TIME < to_timestamp('&2', 'YYYY-MM') + interval '1' month
group by TO_CHAR(a.START_TIME,'YY-MON-DD HH24')
order by TO_CHAR(START_TIME,'YY-MON-DD HH24');
check the format of your inputs &1 and &2 maybe it doesn't match with your date mask: 'YYYY-MM'. Another possible reason is the contents of the table: OPERATION_TYPE and OPERATION_RESULT are both number datatypes? Possible there are storing things different from a number.
I am able to solve the issue using below SQL code:
select TO_CHAR(a.START_TIME,'YY-MON-DD HH24') as Hourly, count(*) AS NbOperations,
SUM(CASE WHEN OPERATION_RESULT=0 THEN 1 ELSE 0 END) AS Success,
SUM(CASE WHEN OPERATION_RESULT=200 THEN 1 ELSE 0 END) AS Cancel,
SUM(CASE WHEN OPERATION_RESULT=203 THEN 1 ELSE 0 END) AS AppletInternalError,
SUM(CASE WHEN OPERATION_RESULT=406 THEN 1 ELSE 0 END) AS TimeoutWaitForCard,
SUM(CASE WHEN OPERATION_RESULT=413 THEN 1 ELSE 0 END) AS BillingError,
SUM(CASE WHEN OPERATION_RESULT=1000 THEN 1 ELSE 0 END) AS ABANDONNED,
SUM(CASE WHEN OPERATION_RESULT=1004 THEN 1 ELSE 0 END) AS ABANDON_FOR_NEW_OPERATION,
SUM(CASE WHEN OPERATION_RESULT NOT IN (0,200,203,406,413,1000,1004) THEN 1 ELSE 0 END) AS NbOthers
from gsg3_invocation_history a, GSG3_OPERATION_TYPE b where START_TIME >= to_timestamp('&1', 'YYYY-MM')
and START_TIME < to_timestamp('&2', 'YYYY-MM') + interval '1' month and OPERATION_TYPE in (2,3,4,5) and a.OPERATION_TYPE=b.OPERATION_ID
group by TO_CHAR(a.START_TIME,'YY-MON-DD HH24') order by TO_CHAR(START_TIME,'YY-MON-DD HH24');

oracle SQL procedure updating table

I need to update the the following columns in a table. males,females,infants and children using SQL procedure.from this column paxtype which has f,i,m,c.which is females,infants,males and children repectively.but am not able error ORA-00907: missing right parenthesis
update xxxx a set (a.INFANTS,a.MALES,a.CHILDREN,a.FEMALES)=
(SELECT b.PAXTYPE, COUNT (b.PAXTYPE) FROM xxxx b
(case ( count (b.PAXTYPE))
when ( count (b.PAXTYPE))='M'then 'a.males'
when ( count (b.PAXTYPE))='F' then 'a.females'
when ( count (b.PAXTYPE))='I' then 'a.infants'
when ( count (b.PAXTYPE))='C' then 'a.children'
END)
WHERE a.date_key = TO_CHAR (b.FLIGHTDATE, 'RRRRMMDD')
AND a.FLTNUM_KEY = TRIM (SUBSTR (b.flightnumber, 3))
AND a.origin = b.frm
AND a.destination = b.too
--and a.date_key=20170801
--and fightnumber = '100'
AND TRIM (a.cancelled) IS NULL
-- and rownum = 1
GROUP BY b.PAXTYPE;
)
It looks like you want a total count of each type, right? I think this is what you want to do.
update xxxx a set (a.INFANTS,a.MALES,a.CHILDREN,a.FEMALES)=
(SELECT
sum(case when b.PAXTYPE = 'I' then 1 else 0 end) as infants_count,
sum(case when b.PAXTYPE = 'M' then 1 else 0 end) as males_count,
sum(case when b.PAXTYPE = 'C' then 1 else 0 end) as children_count,
sum(case when b.PAXTYPE = 'F' then 1 else 0 end) as females_count
FROM xxxx b
WHERE a.date_key = TO_CHAR (b.FLIGHTDATE, 'RRRRMMDD')
AND a.FLTNUM_KEY = TRIM (SUBSTR (b.flightnumber, 3))
AND a.origin = b.frm
AND a.destination = b.too
--and a.date_key=20170801
--and fightnumber = '100'
AND TRIM (a.cancelled) IS NULL
-- and rownum = 1
GROUP BY b.PAXTYPE);

Working with effective dated records

How to fetch an Employees, say 5 latest Action_reason rows which are in an effective dated record, no future rows, should select only current and history rows(effective date <= sysdate). Can I fetch these in single row or will it be 5 rows for an Employee?
select emplid, effdt, action_reasons
-- we have to build a logic here.
-- Should we initialize 5 ACT variables to fetch rows into it?
-- Please help
from JOB
where emplid = '12345'
and effdt <= sysdate.
SELECT LTRIM(SYS_CONNECT_BY_PATH(emplid || ', ' || effdt || ', ' || action_reasons, ', '), ', ')
FROM (
SELECT
FROM (
SELECT emplid, effdt, action_reasons, ROW_NUMBER() OVER (ORDER BY effdt) AS rn
FROM JOB
WHERE emplid= '12345'
AND effdt <= SYSDATE
)
WHERE rn <= 5
)
WHERE CONNECT_BY_ISLEAF = 1
START WITH
rn = 1
CONNECT BY
rn = PRIOR rn + 1
SELECT JOBXX.EMPLID,JOBXX.EFFDT,JOBXX.ACT1,JOBXX.ACT2,JOBXX.ACT3,JOBXX.ACT4,JOBXX.ACT5
FROM
(SELECT SD.EMPLID,
SD.EFFDT,
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 1 THEN SD.A1 ELSE 0 END)),1,2)) ||
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 1 THEN SD.A1 ELSE 0 END)),3,2)) ||
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 1 THEN SD.A1 ELSE 0 END)),5,2))
AS ACT1,
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 2 THEN SD.A1 ELSE 0 END)),1,2)) ||
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 2 THEN SD.A1 ELSE 0 END)),3,2)) ||
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 2 THEN SD.A1 ELSE 0 END)),5,2))
AS ACT2,
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 3 THEN SD.A1 ELSE 0 END)),1,2)) ||
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 3 THEN SD.A1 ELSE 0 END)),3,2)) ||
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 3 THEN SD.A1 ELSE 0 END)),5,2))
AS ACT3,
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 4 THEN SD.A1 ELSE 0 END)),1,2)) ||
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 4 THEN SD.A1 ELSE 0 END)),3,2)) ||
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 4 THEN SD.A1 ELSE 0 END)),5,2))
AS ACT4,
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 5 THEN SD.A1 ELSE 0 END)),1,2)) ||
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 5 THEN SD.A1 ELSE 0 END)),3,2)) ||
CHR(SUBSTR(TO_CHAR(SUM(CASE WHEN SD.R3 = 5 THEN SD.A1 ELSE 0 END)),5,2))
AS ACT5
FROM (
SELECT EMPLID,EFFDT,ACTION_REASON,
SUBSTR(ACTION_REASON,1,1),
SUBSTR(ACTION_REASON,2,1),
SUBSTR(ACTION_REASON,3,1),
TO_NUMBER(ASCII(SUBSTR(ACTION_REASON,1,1)) ||
ASCII(SUBSTR(ACTION_REASON,2,1)) ||
ASCII(SUBSTR(ACTION_REASON,3,1))) AS A1,
ROW_NUMBER() over(PARTITION BY EMPLID,EFFDT ORDER BY EFFDT desc,EFFSEQ desC) R3
FROM PS_JOB
WHERE action in ('ABC','XYZ')
and action_reason in ('123','456','789')
and emplid IN('12345','ABCDE')
AND effdt between '01-jan-2008' and '18-dec-2008'
ORDER BY EFFDT DESC, EFFSEQ DESC
) SD
GROUP BY EMPLID , EFFDT
) JOBXX
You can have the data any way you wish. If you want it as five rows then you could use this:
select * from (
select emplid, empl_rcd, effdt, action_reason
, rank() over (partition by emplid, empl_rcd
order by effdt desc, effseq desc) rank1
from ps_job
where emplid = '12345'
and effdt <= sysdate)
where rank1 <= 5
If you want the data all on a single line then use Oracle's LAG analytic function, thus:
select * from (
select emplid, empl_rcd, effdt
, lag(effdt) over(partition by emplid, empl_rcd order by effdt, effseq) effdt_lag1
, lag(effdt, 2) over(partition by emplid, empl_rcd order by effdt, effseq) effdt_lag2
, lag(effdt, 3) over(partition by emplid, empl_rcd order by effdt, effseq) effdt_lag3
, lag(effdt, 4) over(partition by emplid, empl_rcd order by effdt, effseq) effdt_lag4
, action_reason
, lag(action_reason) over(partition by emplid, empl_rcd order by effdt, effseq) action_reason_lag1
, lag(action_reason, 2) over(partition by emplid, empl_rcd order by effdt, effseq) action_reason_lag2
, lag(action_reason, 3) over(partition by emplid, empl_rcd order by effdt, effseq) action_reason_lag3
, lag(action_reason, 4) over(partition by emplid, empl_rcd order by effdt, effseq) action_reason_lag4
from ps_job
where emplid = '12345') j
where effdt = (
select max(j1.effdt) from ps_job j1
where j1.emplid = j.emplid
and j1.empl_rcd = j.empl_rcd
and j1.effdt <= sysdate)
This gives the last 5 effdt values and the last 5 action reason values. If you don't need both the above SQL can be trimmed accordingly.

Resources