Working with effective dated records - oracle

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.

Related

How to compare 2 columns and return the difference in oracle SQL

We have 2 columns in one table in oracle SQL as
Col1= "there is book on the table"
Col2= "there are flowers on the chair"
Now I need the result as differed data in the column3 as new column col3.
The col3 result should be
"are flowers chair".
How to achieve this in oracle SQL??
You can use:
WITH words ( rid, col, name, id, word ) AS (
SELECT rid,
CASE INSTR(col, ' ')
WHEN 0
THEN NULL
ELSE SUBSTR(col, INSTR(col, ' ') + 1)
END,
name,
1,
CASE INSTR(col, ' ')
WHEN 0
THEN col
ELSE SUBSTR(col, 1, INSTR(col, ' ') - 1)
END
FROM ( SELECT ROWID AS rid, col1, col2 FROM table_name )
UNPIVOT ( col FOR name IN (col1, col2) )
UNION ALL
SELECT rid,
CASE INSTR(col, ' ')
WHEN 0
THEN NULL
ELSE SUBSTR(col, INSTR(col, ' ') + 1)
END,
name,
id + 1,
CASE INSTR(col, ' ')
WHEN 0
THEN col
ELSE SUBSTR(col, 1, INSTR(col, ' ') - 1)
END
FROM words
WHERE col IS NOT NULL
),
paired_words ( rid, id1, id2 ) AS (
SELECT c1.rid,
c1.id AS id1,
c2.id AS id2
FROM ( SELECT rid, id, word FROM words WHERE name = 'COL1' ) c1
INNER JOIN
( SELECT rid, id, word FROM words WHERE name = 'COL2' ) c2
ON (c1.rid = c2.rid AND c1.word = c2.word)
),
max_path ( rid, path ) AS (
SELECT rid,
path
FROM (
SELECT rid,
SYS_CONNECT_BY_PATH(id2, ',') || ',' AS path,
ROW_NUMBER() OVER (PARTITION BY rid ORDER BY LEVEL DESC) AS rn
FROM paired_words
CONNECT BY PRIOR rid = rid
AND PRIOR id1 < id1
AND PRIOR id2 < id2
)
WHERE rn = 1
)
SELECT LISTAGG(word, ' ') WITHIN GROUP (ORDER BY id) AS missing
FROM words w
WHERE NOT EXISTS (
SELECT 1
FROM max_path mp
WHERE w.rid = mp.rid
AND mp.path LIKE '%,' || w.id || ',%'
)
AND w.name = 'COL2'
GROUP BY rid;
Which, for the sample data:
CREATE TABLE table_name ( col1, col2 ) AS
SELECT 'there is book on the table', 'there are flowers on the chair' FROM DUAL UNION ALL
SELECT 'there is book on the table', 'there is a book on the table' FROM DUAL UNION ALL
SELECT 'there is book on the table', 'there is book there is book on the table on the table' FROM DUAL
Outputs:
MISSING
are flowers chair
a
there is book on the table
db<>fiddle here
Here's one option (which follows what you asked). Read comments within code.
SQL> with test (id, col1, col2) as
2 (select 1, 'there is book on the table',
3 'there are flowers on the chair'
4 from dual
5 ),
6 -- split sentences into words (each in its own line)
7 sent1 as
8 (select id,
9 column_value cv,
10 regexp_substr(col1, '[^ ]+', 1, column_value) word
11 from test cross join
12 table(cast(multiset(select level from dual
13 connect by level <= regexp_count(col1, ' ') + 1
14 ) as sys.odcinumberlist))
15 ),
16 sent2 as
17 (select id,
18 column_value cv,
19 regexp_substr(col2, '[^ ]+', 1, column_value) word
20 from test cross join
21 table(cast(multiset(select level from dual
22 connect by level <= regexp_count(col2, ' ') + 1
23 ) as sys.odcinumberlist))
24 )
25 -- final result
26 select a.id,
27 listagg(b.word, ' ') within group (order by a.cv) result
28 from sent2 b join sent1 a on a.id = b.id and a.cv = b.cv and a.word <> b.word
29 group by a.id;
ID RESULT
---------- ------------------------------
1 are flowers chair
SQL>

ORA-01427 Single-Row Subquery Returns More than One Row - how to resolve?

I've had this query running for over 2 years and just recently this began throwing the ORA-01427 single row sub-query returns multiple rows error. What's the best way to debug this when there are multiple sub-queries? Should I be adding a MAX statement to each subquery? I've tried switching some of the = operators to IN but that's not working and I'm not confident it would give me the correct results either.
Appreciate any insight or assistance this community can provide. I'm ripping my hair out working through this one!
SELECT
NVL(
(SELECT
'Y'
FROM
PER_ASSIGNMENT_SUPERVISORS_F
WHERE
MANAGER_ID = PAPF.PERSON_ID
AND MANAGER_TYPE ='LINE_MANAGER'
AND TRUNC(SYSDATE) BETWEEN EFFECTIVE_START_DATE AND EFFECTIVE_END_DATE
AND ROWNUM = 1),'N') MANAGER_FLAG,
PAAM.ASSIGNMENT_STATUS_TYPE,
PAAM.EMPLOYMENT_CATEGORY,
TO_CHAR(PPOS.DATE_START,'YYYY-MM-DD') AS HIRE_DATE,
PER_EXTRACT_UTILITY.GET_STANDARD_WORKING_HOURS(PAAM.ASSIGNMENT_ID,TRUNC(SYSDATE)) AS STANDARD_WORKING_HOURS,
TO_CHAR(PAAM.EFFECTIVE_START_DATE,'YYYY-MM-DD') AS EFFECTIVE_START_DATE,
(
SELECT
PJFVL.JOB_CODE
FROM
PER_ALL_ASSIGNMENTS_M PAAM1,
PER_JOBS_F_VL PJFVL
WHERE
PAAM1.PERSON_ID = PASF.MANAGER_ID
AND TRUNC(SYSDATE) BETWEEN PAAM1.EFFECTIVE_START_DATE AND PAAM1.EFFECTIVE_END_DATE
AND TRUNC(SYSDATE) BETWEEN PJFVL.EFFECTIVE_START_DATE AND PJFVL.EFFECTIVE_END_DATE
and PAAM1.ASSIGNMENT_STATUS_TYPE='ACTIVE'
AND PAAM1.ASSIGNMENT_TYPE = 'E'
AND PAAM1.effective_latest_change = 'Y'
AND PJFVL.JOB_ID = PAAM1.JOB_ID
)as Manager_job_code,
(
SELECT
HOIF.ORG_INFORMATION1
FROM
PER_ALL_ASSIGNMENTS_M PAAM2,
HR_ORGANIZATION_INFORMATION_F HOIF
WHERE
PAAM2.PERSON_ID = PASF.MANAGER_ID
AND HOIF.ORG_INFORMATION_CONTEXT = 'DEPT_DET'
and PAAM2.ASSIGNMENT_STATUS_TYPE='ACTIVE'
AND PAAM2.ASSIGNMENT_TYPE = 'E'
AND PAAM2.effective_latest_change = 'Y'
AND TRUNC(SYSDATE) BETWEEN PAAM2.EFFECTIVE_START_DATE AND PAAM2.EFFECTIVE_END_DATE
AND TRUNC(SYSDATE) BETWEEN HOIF.EFFECTIVE_START_DATE AND HOIF.EFFECTIVE_END_DATE
AND HOIF.ORGANIZATION_ID = PAAM2.ORGANIZATION_ID
) as Manager_dep_code,
(SELECT
COUNT(PPOS.PERIOD_OF_SERVICE_ID)
FROM
PER_PERIODS_OF_SERVICE PPOS
WHERE
1 = 1
AND PAAM.PERSON_ID = PPOS.PERSON_ID
) AS INACTIVE_WORKRELATIONSHIP,
PAPF.PERSON_NUMBER as SAMACCOUNTNAME,
(SELECT CSB.NAME FROM
CMP_SALARY CS,
CMP_SALARY_BASES CSB
WHERE
CS.ASSIGNMENT_ID = PAAM.ASSIGNMENT_ID
AND CS.SALARY_BASIS_ID = CSB.SALARY_BASIS_ID
and TRUNC(SYSDATE) BETWEEN CS.DATE_FROM AND CS.DATE_TO
) AS hourly_salary_Paid,
TO_CHAR(PP.DATE_OF_BIRTH,'YYYY-MM-DD') AS DOB,
PPNFV.LAST_NAME,
PPNFV.FIRST_NAME,
HLA.LOCATION_NAME as Location,
HLA.ADDRESS_LINE_1 AS LOC_ADDRESS_1,
HLA.ADDRESS_LINE_2 AS LOC_ADDRESS_2,
HLA.TOWN_OR_CITY AS City,
HLA.POSTAL_CODE AS ZIP_CODE,
HLA.REGION_2 AS STATE,
PPNFV.KNOWN_AS AS PREFERRED_NAME,
TRIM((PPNFV.KNOWN_AS||' '||PPNFV.LAST_NAME)) AS PREFERRED_NAME_LAST_NAME,
(SELECT
PPNFV.DISPLAY_NAME
FROM per_person_names_f_v PPNFV
WHERE 1 = 1
AND PPNFV.PERSON_ID = PASF.MANAGER_ID
AND PPNFV.NAME_TYPE='GLOBAL'
AND TRUNC(SYSDATE) BETWEEN PPNFV.EFFECTIVE_START_DATE AND PPNFV.EFFECTIVE_END_DATE
) AS MANAGER_NAME,
(SELECT
PAPF.PERSON_NUMBER
FROM PER_ALL_PEOPLE_F PAPF
WHERE PAPF.PERSON_ID = PASF.MANAGER_ID
AND TRUNC(SYSDATE) BETWEEN PAPF.EFFECTIVE_START_DATE AND PAPF.EFFECTIVE_END_DATE
) AS MANAGER_NUMBER,
HAOUFVL.NAME AS DEPARTMENT,
PAAM.ASSIGNMENT_NAME AS JOB_TILE,
PLE.NAME as Company,
PJLG.INFORMATION1 AS FLSA,
SUBSTR(PNI.NATIONAL_IDENTIFIER_NUMBER,-4) AS SSN_NUMBER,
PAAM.ASS_ATTRIBUTE1 as Officer_TITLE,
(
select
bu.name
from
hr_all_organization_units_f_vl bu
where 1 = 1
and paam.business_unit_id = bu.organization_id
and trunc(sysdate) between bu.effective_start_date and bu.effective_end_date
) as BUS_UNIT,
TO_CHAR (PPOS.ORIGINAL_DATE_OF_HIRE,'YYYY-MM-DD') AS ORIGINAL_DATE_OF_HIRE1,
(
CASE WHEN PPLF.SEX = 'F' THEN
'TRUE'
ELSE
'FALSE'
END
) AS GENDER,
(
CASE WHEN PJFFVL.JOB_FAMILY_NAME = 'Executive' THEN
'ELT'
ELSE
' '
END
) AS ELT_DESIGNATION,
HOIF.ORG_INFORMATION1 as DEPATMENT_CODE,
PJFV.JOB_CODE AS JOB_CODE,
PAF.ADDRESS_LINE_1 AS HOME_ADDRESS_LINE_1,
PAF.ADDRESS_LINE_2 AS HOME_ADDRESS_LINE_2,
PAF.TOWN_OR_CITY AS HOW_ADDRESS_CITY,
PAF.REGION_2 AS HOME_ADDRESS_STATE,
PAF.POSTAL_CODE AS HOME_ADRESS_ZIP_CODE,
PGFTL.NAME as Grade_level,
(SELECT
distinct (per_extract_utility.get_decoded_lookup('JOB_FUNCTION_CODE',PJF.JOB_FUNCTION_CODE))
FROM
PER_JOB_SECURED_LIST_V job WHERE TRUNC(SYSDATE) BETWEEN effective_start_date AND effective_end_date
) as JOB_FUNCTION,
pp.attribute1 as PER_NETWORKID,
(SELECT
PPNFV.attribute1
FROM PER_PERSONS PPNFV
WHERE 1 = 1
AND PPNFV.PERSON_ID = PASF.MANAGER_ID
) AS MANAGER_NETWORKID,
HOIF.ORG_INFORMATION2 AS REGION,
to_char(paam.ass_attribute_date1,'MM/DD/YYYY') as OfficerPromoDate
FROM
PER_ALL_ASSIGNMENTS_M PAAM,
PER_ASSIGNMENT_SUPERVISORS_F PASF,
PER_PERIODS_OF_SERVICE PPOS,
PER_ALL_PEOPLE_F PAPF,
PER_PERSONS PP,
per_person_names_f_v PPNFV,
HR_LOCATIONS_ALL HLA,
HR_ALL_ORGANIZATION_UNITS_F_VL HAOUFVL,
PER_JOB_LEG_F PJLG,
PER_NATIONAL_IDENTIFIERS PNI,
PER_PEOPLE_LEGISLATIVE_F PPLF,
PER_JOB_FAMILY_F_VL PJFFVL,
PER_JOBS_F_V PJFV,
HR_ORGANIZATION_INFORMATION_F HOIF,
PER_ADDRESSES_F PAF,
PER_PERSON_ADDR_USAGES_F PPAUF,
PER_GRADES_F_TL PGFTL,
PER_JOBS_F PJF,
PER_LEGAL_EMPLOYERS PLE,
HR_ALL_ORGANIZATION_UNITS_F HAOUF
WHERE
PAAM.ASSIGNMENT_STATUS_TYPE='ACTIVE'
AND PAAM.ASSIGNMENT_TYPE = 'E'
AND PAAM.effective_latest_change = 'Y'
AND PAAM.ASSIGNMENT_ID = PASF.ASSIGNMENT_ID(+)
AND PASF.MANAGER_TYPE (+) = 'LINE_MANAGER'
AND PNI.PERSON_ID(+) = PAAM.PERSON_ID
AND PAAM.PERSON_ID = PPLF.PERSON_ID(+)
and PJFV.JOB_FAMILY_ID= PJFFVL.JOB_FAMILY_ID(+)
AND PJFV.JOB_ID(+) = PAAM.JOB_ID
AND HOIF.ORGANIZATION_ID(+)= PAAM.ORGANIZATION_ID
AND HOIF.ORG_INFORMATION_CONTEXT(+) = 'DEPT_DETAILS'
AND PPAUF.PERSON_ID(+)= PAPF.PERSON_ID
AND PPAUF.ADDRESS_TYPE (+) = 'HOME'
AND PPAUF.ADDRESS_ID= PAF.ADDRESS_ID(+)
AND PGFTL.GRADE_ID(+)= PAAM.GRADE_ID
AND PJF.JOB_ID(+)= PAAM.JOB_ID
AND PJLG.INFORMATION_CATEGORY='HRX_US_JOBS'
and HAOUF.ORGANIZATION_ID(+)=PLE.ORGANIZATION_ID
and PAAM.LEGAL_ENTITY_ID=PLE.ORGANIZATION_ID
AND TRUNC(SYSDATE) BETWEEN PAAM.EFFECTIVE_START_DATE(+) AND PAAM.EFFECTIVE_END_DATE (+)
AND PAAM.PERIOD_OF_SERVICE_ID = PPOS.PERIOD_OF_SERVICE_ID
AND PAPF.PERSON_ID = PAAM.PERSON_ID
AND PP.PERSON_ID = PAAM.PERSON_ID
AND PPNFV.PERSON_ID = PAAM.PERSON_ID
AND HLA.LOCATION_ID(+) = PAAM.LOCATION_ID
AND PJLG.JOB_ID(+) = PAAM.JOB_ID
AND HAOUFVL.ORGANIZATION_ID(+) = PAAM.ORGANIZATION_ID
AND PPNFV.NAME_TYPE = 'GLOBAL'
AND TRUNC(SYSDATE) BETWEEN PPNFV.EFFECTIVE_START_DATE AND PPNFV.EFFECTIVE_END_DATE
AND TRUNC(SYSDATE) BETWEEN PAPF.EFFECTIVE_START_DATE AND PAPF.EFFECTIVE_END_DATE
AND TRUNC(SYSDATE) BETWEEN HAOUFVL.EFFECTIVE_START_DATE(+) AND HAOUFVL.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN PPLF.EFFECTIVE_START_DATE(+) AND PPLF.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN PJFFVL.EFFECTIVE_START_DATE(+) AND PJFFVL.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN PJFV.EFFECTIVE_START_DATE(+) AND PJFV.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN HOIF.EFFECTIVE_START_DATE(+) AND HOIF.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN PAF.EFFECTIVE_START_DATE(+) AND PAF.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN PPAUF.EFFECTIVE_START_DATE(+) AND PPAUF.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN PGFTL.EFFECTIVE_START_DATE(+) AND PGFTL.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN PJF.EFFECTIVE_START_DATE(+) AND PJF.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN PLE.EFFECTIVE_START_DATE AND PLE.EFFECTIVE_END_DATE
AND TRUNC(SYSDATE) BETWEEN HAOUF.EFFECTIVE_START_DATE(+) AND HAOUF.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN HLA.EFFECTIVE_START_DATE(+) AND HLA.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN PJLG.EFFECTIVE_START_DATE(+) AND PJLG.EFFECTIVE_END_DATE(+)
AND TRUNC(SYSDATE) BETWEEN PASF.EFFECTIVE_START_DATE(+) AND PASF.EFFECTIVE_END_DATE(+)
ORDER BY PAPF.PERSON_NUMBER
Run the query in a SQL client that will generate a more detailed error message. For example, the below code is run in SQL*Plus, which correctly indicates that the problem is with the subquery on line 3.
SQL> select
2 (select 1 from dual) this_will_work,
3 (select 1 from dba_objects) this_will_fail,
4 (select 1 from dual) this_will_work
5 from dual;
(select 1 from dba_objects) this_will_fail,
*
ERROR at line 3:
ORA-01427: single-row subquery returns more than one row

How To - SELECT additional rows based on fiscal begin date and end date

I need to split each row into x rows based on begin_dt and end_dt of the fiscal year.
Can this be done in oracle ?
Script I used
As you see, they are not dynamic. A lot of copy and paste for each pp column and I need to know my data in advance.
If I don't have any option, how do I move data in the column and put in the row instead?
Will pivot or unpivot fix the issue?
This is the base table
ANIMAL BEGIN_DT END_DT
-------- --------- ----------
dog 9/1/2017 6/30/2018
pig 7/15/1999 5/28/2001
cat 3/1/2018 1/27/2020
This is what I have so far
ANIMAL ORG_BEGIN_DT ORG_END_DT BP1 B1 E1 BP2 B2 E2 BP3 B3 E3
---- ------------ ------------ ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
dog 09/01/2017 09/01/2017 FY2018 09/01/2017 06/30/2018
pig 07/15/1999 07/15/1999 FY2000 07/15/1999 06/30/2000 FY2001 07/01/2000 05/28/2001
cat 03/01/2018 03/01/2018 FY2018 03/01/2018 06/30/2018 FY2019 07/01/2018 06/30/2019 FY2019 07/01/2019 01/27/2020
SET LINESIZE 32000;
column animal format a6
column ORG_BEGIN_DT format a12
column ORG_END_DT format a12
column BP1 format a10
column BP2 format a10
column BP3 format a10
column B1,B2,B3 format a17
column E1,E2,E3 format a17
CREATE TABLE SRCTBL (ANIMAL VARCHAR2(25) NOT NULL,
PERIOD_ID VARCHAR2(12) NOT NULL,
BEGIN_DT DATE,
END_DT DATE)
/
insert into SRCTBL values ( 'dog', ' ', to_date('9/1/2017','MM/DD/YYYY') , to_date('6/30/2018','MM/DD/YYYY' ));
insert into SRCTBL values ( 'pig', ' ', to_date('7/15/1999','MM/DD/YYYY'), to_date('5/28/2001','MM/DD/YYYY' ));
insert into SRCTBL values ( 'cat', ' ', to_date('3/1/2018','MM/DD/YYYY') , to_date('1/27/2020','MM/DD/YYYY' ));
commit;
with awrd as (select * from SRCTBL )
, pr as (select w.animal
, extract (month from w.begin_dt) begin_mon
, extract (month from w.end_dt) end_mon
, round(MONTHS_BETWEEN (w.end_dt ,w.begin_dt)) mth_dur
, round((w.end_dt - w.begin_dt)/365, 2) yr_dur
, case when extract ( month from w.begin_dt ) in (7,8,9,10,11,12)
then extract ( year from w.begin_dt ) + 1
else extract ( year from w.begin_dt ) end begin_yr
, case when extract ( month from w.end_dt ) in (7,8,9,10,11,12)
then extract ( year from w.end_dt ) + 1
else extract ( year from w.end_dt ) end AS end_yr
from SRCTBL w )
, calc as ( select pr.animal, begin_mon, end_mon , mth_dur , yr_dur ,begin_yr, end_yr from pr)
, pp1 as ( select calc.animal
, 'GFY-' || calc.begin_yr Budget_Period
, awrd.begin_dt
, case when calc.begin_mon >= 7 and calc.begin_yr = calc.end_yr and calc.end_mon > 6 then awrd.end_dt
when calc.begin_mon >= 7 and calc.begin_yr = calc.end_yr and calc.end_mon < 7 then awrd.end_dt
when calc.begin_mon >= 7 and calc.begin_yr <> calc.end_yr and calc.end_mon <= 7 then LAST_DAY ('30-JUN-'|| calc.begin_yr )
when calc.begin_mon >= 7 and calc.begin_yr <> calc.end_yr and calc.end_mon > 7 then LAST_DAY ('30-JUN-'|| calc.begin_yr )
when calc.begin_mon < 7 and awrd.end_dt > LAST_DAY ('30-JUN-'|| calc.begin_yr) then LAST_DAY ('30-JUN-'|| calc.begin_yr )
else awrd.end_dt end end_dt
from calc, awrd
where calc.animal= awrd.animal)
, pp2 as ( select pp1.animal
, case when awrd.end_dt = pp1.end_dt then NULL else 'GFY-' || to_char(to_number (calc.begin_yr) + 1) end Budget_Period
, case when awrd.end_dt = pp1.end_dt then NULL else pp1.end_dt + 1 end begin_dt
, case when awrd.end_dt = pp1.end_dt then NULL
when awrd.end_dt < LAST_DAY ('30-JUN-'|| to_char(to_number (calc.begin_yr) + 1)) then awrd.end_dt
else LAST_DAY ('30-JUN-'|| to_char(to_number (calc.begin_yr) + 1)) end end_dt
from pp1 , calc , awrd
where calc.animal = awrd.animal
and calc.animal = pp1.animal )
, pp3 as ( select pp2.animal
, case when awrd.end_dt = pp2.end_dt then NULL
when pp2.end_dt is null then NULL
else 'GFY-' || to_char(to_number (calc.begin_yr) + 1) end Budget_Period
, case when awrd.end_dt = pp2.end_dt then NULL else pp2.end_dt + 1 end begin_dt
, case when awrd.end_dt = pp2.end_dt then NULL
when pp2.end_dt is null then NULL
when awrd.end_dt < LAST_DAY ('30-JUN-'|| to_char(to_number (calc.begin_yr) + 2)) then awrd.end_dt
else LAST_DAY ('30-JUN-'|| to_char(to_number (calc.begin_yr) + 2)) end end_dt
from pp2 , calc , awrd
where calc.animal = awrd.animal
and calc.animal = pp2.animal )
select a.animal TYPE
, a.begin_dt, a.end_dt
, pp1.budget_period, pp1.begin_dt, pp1.end_dt
, pp2.budget_period, pp2.begin_dt, pp2.end_dt
, pp3.budget_period, pp3.begin_dt, pp3.end_dt
from awrd A , pp1, pp2, pp3
where a.animal = pp1.animal
and a.animal = pp2.animal
and a.animal = pp3.animal;
This is the result I need
ANIMAL FISCAL_YEAR BEGIN_DT END_DT
-------- --------- ---------- ----------
dog FY2018 9/1/2017 6/30/2018
pig FY2000 7/15/1999 6/30/2000
pig FY2001 7/1/2000 5/28/2001
cat FY2018 3/1/2018 6/30/2018
cat FY2019 7/1/2018 6/30/2019
cat FY2020 7/1/2019 1/27/2020
Thank you #Hanna, it works.
select s.animal , 'GFY-' || extract ( year from fy.end_dt ) period_id
, case when s.begin_dt > fy.begin_dt then s.begin_dt else fy.begin_dt end begin_dt
, case when s.end_dt > fy.end_dt then fy.end_dt else s.end_dt end end_dt
from srctbl s, fiscal_years fy
where (( s.begin_dt between fy.begin_dt and fy.end_dt )
or ( s.end_dt between fy.begin_dt and fy.end_dt )
or ( s.begin_dt < fy.begin_dt and s.end_dt > fy.end_dt ))
order by 1,2;```
This is how I would do it. Basically, you need a row source for your fiscal years. Here, I'm doing that on the fly inside a Common Table Expression. (I've made the range of fiscal years a bit larger than necessary because I'm too lazy to do the math.) You could also create an explicit table.
with fiscal_years as (
select 'FY' || to_char(1995+level) as fy_name,
to_date( '07/01/' || to_char(1995+level-1), 'MM/DD/YYYY' ) as begin_dt,
to_date( '06/30/' || to_char(1995+level), 'MM/DD/YYYY' ) as end_dt
from dual
connect by level <= 40
)
select s.animal, fy.begin_dt, fy.end_dt
from srctbl s
inner join fiscal_years fy
on ( s.begin_dt between fy.begin_dt and fy.end_dt )
or ( s.end_dt between fy.begin_dt and fy.end_dt )
or ( s.begin_dt < fy.begin_dt and s.end_dt > fy.end_dt )
SQL Fiddle

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

Concatenate columns with distinct values in oracle

Gurus,
My table structre look like follwoing:
TankListUS TankListCanada TankListIndia
---------- -------------- -------------
T111||T222 T444||T222 T555
Now when I run the query:
select (TL.TankListUS || '||' || TL.TankListCanada || '||' || TL.TankListIndia)as "OverallSummary" from TankListTL
I get output as
T111||T222||T444||T222||T555
But I don't need duplicate of tanks. I need my output as:
T111||T222||T444||T555
Is this possible?
I have not tested this but try the following :-
with test1 as
(select (TL.TankListUS || '||' || TL.TankListCanada || '||' || TL.TankListIndia) as str from TankListTL),
test2 as
(select regexp_substr(str,'[^|]+',1,rownum) split
from test1
connect by level <= length (regexp_replace (str, '[^|]+')) + 1)
select listagg(split,'||') within group(order by split)
from test2
Do note that listagg was introduced in Oracle 11gR2. Following are some of the string aggregation techniques :-
http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php#listagg
Source:
TANKLISTUS TANKLISTCANADA TANKLISTINDIA
T111||T222 T444||T222 T555
T111||T222 T444||T111 T555
T111||T666 T444||T222 T555
Code:
WITH src AS
(
SELECT 'T111||T222' TankListUS, 'T444||T222' TankListCanada, 'T555' TankListIndia FROM DUAL UNION ALL
SELECT 'T111||T222' TankListUS, 'T444||T111' TankListCanada, 'T555' TankListIndia FROM DUAL UNION ALL
SELECT 'T111||T666' TankListUS, 'T444||T222' TankListCanada, 'T555' TankListIndia FROM DUAL
)
, step1 AS
(
SELECT SUBSTR(TankListUS, 1, 4) AS us1
, SUBSTR(TankListUS, 7) AS us2
, SUBSTR(TankListCanada, 1, 4) AS ca1
, SUBSTR(TankListCanada, 7) AS ca2
, TankListIndia AS in1
, ROWNUM AS r_id
FROM src
)
, step2 AS
(
SELECT us1 AS r_value, r_id FROM step1 UNION
SELECT us2, r_id FROM step1 UNION
SELECT ca1, r_id FROM step1 UNION
SELECT ca2, r_id FROM step1 UNION
SELECT in1, r_id FROM step1
)
,step3 AS
(
SELECT r_value
, LEAD(r_value, 1) OVER (PARTITION BY r_id ORDER BY r_value) AS lead1
, LEAD(r_value, 2) OVER (PARTITION BY r_id ORDER BY r_value) AS lead2
, LEAD(r_value, 3) OVER (PARTITION BY r_id ORDER BY r_value) AS lead3
, LEAD(r_value, 4) OVER (PARTITION BY r_id ORDER BY r_value) AS lead4
, ROW_NUMBER() OVER (PARTITION BY r_id ORDER BY r_value) AS r_num
FROM step2
)
,step4 AS
(
SELECT r_value
|| NVL2(lead1, '||' || lead1, lead1)
|| NVL2(lead2, '||' || lead2, lead2)
|| NVL2(lead3, '||' || lead3, lead3)
|| NVL2(lead4, '||' || lead4, lead4) AS the_result
FROM step3
WHERE r_num = 1
)
-- OR:
SELECT DISTINCT the_result AS the_result_with_DISTINCT
FROM step4
Result:
T111||T222||T444||T555||T666
T111||T222||T444||T555
with t1 as (select 'T111||T222||T444||T222||T555' col from dual),
t2 as (SELECT rownum,REGEXP_SUBSTR (col, '[^||]+', 1, RN) SPLIT
from t1
cross join
(SELECT ROWNUM RN
FROM (SELECT (length(REGEXP_REPLACE (col, '[^||]+'))/2)+1 MAX_VALUE
from t1)
connect by level <= max_value)),
t3 as (select distinct split as dis_col from t2)
select
rtrim (xmlagg (xmlelement (e, dis_col || '||')).extract ('//text()'), '||') d_col
from
t3;

Resources