Reputation: 599
I want to fetch the latest ACTIVE STATUS TYPE WITH ACTION_CODE HIRE OR IF THE STATUS_TYPE HAS CHANGED FROM INACTIVE TO ACTIVE, then the query should fetch the first record just after the INACTIVE status.
for example, shown below
ACTION_CODE HIRE
with status_type ACTIVE
i..e if there is no change in the status_type of the employee_number, then the first row. ACTION_CODE ASG_CHANGE
AND START_DATE 07-AUG-2019
with status_type ACTIVE
i.e. first effective_start_date after the "INACTIVE" STATUS_TYPE. ACTION_CODE GLB_TRANSFER
and start_date 07-AUG-2019
with status_type ACTIVE
INACTIVE
.asg_table :
employee_number start_Date END_DATE action_code status_type
1 01-JAN-2019 02-JUL-2019 HIRE ACTIVE
1 03-JUL-2019 06-AUG-2019 ASG_CHANGE ACTIVE
1 07-AUG-2019 31-DEC-4712 ASG_CHANGE ACTIVE
employee_number start_Date END_DATE action_code status_type
2 01-JAN-2019 02-JUL-2019 HIRE ACTIVE
2 03-JUN-2019 05-JUL-2019 TERM INACTIVE
2 07-AUG-2019 15-AUG-2019 ASG_CHANGE ACTIVE
2 16-AUG-2019 31-DEC-4712 ASG_CHANGE ACTIVE
employee_number start_Date END_DATE action_code status_type
3 01-JAN-2019 02-JUL-2019 HIRE ACTIVE
3 03-JUN-2019 05-JUL-2019 GLB_TRANSFER INACTIVE
3 07-AUG-2019 15-AUG-2019 GLB_TRANSFER ACTIVE
3 16-AUG-2019 31-DEC-4712 ASG_CHANGE ACTIVE
employee_number start_Date END_DATE action_code status_type
4 01-JAN-2019 02-JUL-2019 HIRE ACTIVE
4 03-JUL-2019 06-AUG-2019 ASG_CHANGE ACTIVE
4 07-AUG-2019 31-DEC-4712 TERM INACTIVE
What approach can I follow to include all the conditions in one query.
Upvotes: 1
Views: 143
Reputation: 14934
The issue is that you require two inflection points from your data: the maximum end date for status Inactive (or an assigned one where there is none) and minimum start date following that event. The following manages both those points.
I do not claim this is the most performant method not the most elegant. However, it is clear and easily followed showing the development of each step.
create table employee_status_hist ( employee_number integer
, start_date date
, end_date date
, action_code varchar2(16)
, status_type varchar2(08)
);
insert into employee_status_hist (employee_number,start_date,end_date,action_code,status_type)
select 1, to_date ('01-JAN-2019','dd-mon-yyyy'), to_date('02-JUL-2019','dd-mon-yyyy'), trim('HIRE '), trim('ACTIVE ') from dual union all
select 1, to_date ('03-JUL-2019','dd-mon-yyyy'), to_date('06-AUG-2019','dd-mon-yyyy'), trim('ASG_CHANGE'), trim('ACTIVE ') from dual union all
select 1, to_date ('07-AUG-2019','dd-mon-yyyy'), to_date('31-DEC-4712','dd-mon-yyyy'), trim('ASG_CHANGE'), trim('ACTIVE ') from dual union all
select 2, to_date ('01-JAN-2019','dd-mon-yyyy'), to_date('02-JUL-2019','dd-mon-yyyy'), trim('HIRE '), trim('ACTIVE ') from dual union all
select 2, to_date ('03-JUN-2019','dd-mon-yyyy'), to_date('05-JUL-2019','dd-mon-yyyy'), trim('TERM '), trim('INACTIVE') from dual union all
select 2, to_date ('07-AUG-2019','dd-mon-yyyy'), to_date('15-AUG-2019','dd-mon-yyyy'), trim('ASG_CHANGE'), trim('ACTIVE ') from dual union all
select 2, to_date ('16-AUG-2019','dd-mon-yyyy'), to_date('31-DEC-4712','dd-mon-yyyy'), trim('ASG_CHANGE'), trim('ACTIVE ') from dual union all
select 3, to_date ('01-JAN-2019','dd-mon-yyyy'), to_date('02-JUL-2019','dd-mon-yyyy'), trim('HIRE '), trim('ACTIVE ') from dual union all
select 3, to_date ('03-JUN-2019','dd-mon-yyyy'), to_date('05-JUL-2019','dd-mon-yyyy'), trim('GLB_TRANSF'), trim('INACTIVE') from dual union all
select 3, to_date ('07-AUG-2019','dd-mon-yyyy'), to_date('15-AUG-2019','dd-mon-yyyy'), trim('GLB_TRANSF'), trim('ACTIVE ') from dual union all
select 3, to_date ('16-AUG-2019','dd-mon-yyyy'), to_date('31-DEC-4712','dd-mon-yyyy'), trim('ASG_CHANGE'), trim('ACTIVE ') from dual union all
select 4, to_date ('01-JAN-2019','dd-mon-yyyy'), to_date('02-JUL-2019','dd-mon-yyyy'), trim('HIRE '), trim('ACTIVE ') from dual union all
select 4, to_date ('03-JUL-2019','dd-mon-yyyy'), to_date('06-AUG-2019','dd-mon-yyyy'), trim('ASG_CHANGE'), trim('ACTIVE ') from dual union all
select 4, to_date ('07-AUG-2019','dd-mon-yyyy'), to_date('31-DEC-4712','dd-mon-yyyy'), trim('TERM '), trim('INACTIVE') from dual ;
with last_inactive as
( select esh.employee_number, max(esh.end_date) end_date
from employee_status_hist esh
where status_type = 'INACTIVE'
group by esh.employee_number
union all
select distinct esh.employee_number, to_date('01-jan-0001','dd-mon-yyyy') end_date
from employee_status_hist esh
where not exists ( select null
from employee_status_hist esh2
where esh.employee_number = esh2.employee_number
and status_type = 'INACTIVE'
)
)
, desired as
( select esh.employee_number, min(esh.start_date) start_date
from employee_status_hist esh
join last_inactive lin
on ( esh.employee_number = lin.employee_number
and esh.start_date > lin.end_date
)
group by esh.employee_number
)
select employee_number, start_date, action_code
from employee_status_hist
where (employee_number, start_date) in
(select employee_number, start_date
from desired
);
Upvotes: 0
Reputation: 665
Use row_number(), like:
SELECT *
FROM
(select mytbl.*,
row_number() over (partition by mytbl.id order by <condition order> ) rn
from mytbl) a
WHERE a.rn = 1
example:
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=f5e43c0f001657f1bd17fb89186df6ef
with mytbl as
(select 1 id,
TO_DATE('01-JAN-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('02-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'HIRE' action_code,
'ACTIVE' status_type FROM dual
union all
select 1 id,
TO_DATE('03-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('06-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'ASG_CHANGE' action_code,
'ACTIVE' status_type FROM dual
union all
select 1 id,
TO_DATE('07-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('31-DEC-4712', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'ASG_CHANGE' action_code,
'ACTIVE' status_type FROM dual
union all
select 2 id,
TO_DATE('01-JAN-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('02-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'HIRE' action_code,
'ACTIVE' status_type FROM dual
union all
select 2 id,
TO_DATE('03-JUN-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('02-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'TERM' action_code,
'INACTIVE' status_type FROM dual
union all
select 2 id,
TO_DATE('07-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('15-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'ASG_CHANGE' action_code,
'ACTIVE' status_type FROM dual
union all
select 2 id,
TO_DATE('16-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('31-DEC-4712', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'ASG_CHANGE' action_code,
'ACTIVE' status_type FROM dual
union all
select 3 id,
TO_DATE('01-JAN-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('02-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'HIRE' action_code,
'ACTIVE' status_type FROM dual
union all
select 3 id,
TO_DATE('03-JUN-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('05-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'GLB_TRANSFER' action_code,
'INACTIVE' status_type FROM dual
union all
select 3 id,
TO_DATE('07-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('15-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'GLB_TRANSFER' action_code,
'ACTIVE' status_type FROM dual
union all
select 3 id,
TO_DATE('16-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('31-DEC-4712', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'ASG_CHANGE' action_code,
'ACTIVE' status_type FROM dual)
SELECT *
FROM
(select mytbl.*,
row_number() over (partition by mytbl.id
order by
case when mytbl.ACTION_CODE = 'GLB_TRANSFER'
and mytbl.start_date = TO_DATE('07-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American')
and status_type = 'ACTIVE' then 0
else 1 end) rn
from mytbl) a
WHERE a.rn = 1
It's true for 3th. I think you have general condition
OUTPUT:
1 01.01.2019 02.07.2019 HIRE ACTIVE 1
2 01.01.2019 02.07.2019 HIRE ACTIVE 1
3 07.08.2019 15.08.2019 GLB_TRANSFER ACTIVE 1
also:
with mytbl as
(select 1 id,
TO_DATE('01-JAN-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('02-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'HIRE' action_code,
'ACTIVE' status_type FROM dual
union all
select 1 id,
TO_DATE('03-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('06-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'ASG_CHANGE' action_code,
'ACTIVE' status_type FROM dual
union all
select 1 id,
TO_DATE('07-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('31-DEC-4712', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'ASG_CHANGE' action_code,
'ACTIVE' status_type FROM dual
union all
select 2 id,
TO_DATE('01-JAN-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('02-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'HIRE' action_code,
'ACTIVE' status_type FROM dual
union all
select 2 id,
TO_DATE('03-JUN-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('02-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'TERM' action_code,
'INACTIVE' status_type FROM dual
union all
select 2 id,
TO_DATE('07-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('15-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'ASG_CHANGE' action_code,
'ACTIVE' status_type FROM dual
union all
select 2 id,
TO_DATE('16-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('31-DEC-4712', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'ASG_CHANGE' action_code,
'ACTIVE' status_type FROM dual
union all
select 3 id,
TO_DATE('01-JAN-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('02-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'HIRE' action_code,
'ACTIVE' status_type FROM dual
union all
select 3 id,
TO_DATE('03-JUN-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('05-JUL-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'GLB_TRANSFER' action_code,
'INACTIVE' status_type FROM dual
union all
select 3 id,
TO_DATE('07-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('15-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'GLB_TRANSFER' action_code,
'ACTIVE' status_type FROM dual
union all
select 3 id,
TO_DATE('16-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('31-DEC-4712', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'ASG_CHANGE' action_code,
'ACTIVE' status_type FROM dual
union all
select 3 id,
TO_DATE('16-AUG-2019', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('31-DEC-4712', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'ASG_CHANGE' action_code,
'ACTIVE' status_type FROM dual
union all
select 4 id,
TO_DATE('01-AUG-2018', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('31-DEC-4712', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'HIRE' action_code,
'ACTIVE' status_type FROM dual
union all
select 4 id,
TO_DATE('21-AUG-2018', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('31-DEC-4712', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'TRANSFER' action_code,
'INACTIVE' status_type FROM dual
union all
select 4 id,
TO_DATE('21-AUG-2018', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('31-DEC-4712', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'TRANSFER' action_code,
'ACTIVE' status_type FROM dual
union all
select 4 id,
TO_DATE('01-NOV-2018', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') start_date,
TO_DATE('31-DEC-4712', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = American') end_date,
'CHANGE_ASG' action_code,
'ACTIVE' status_type FROM dual)
SELECT a.id, a.start_date, a.end_date, a.action_code, a.status_type
FROM
(SELECT a.id, a.start_date, a.end_date, a.action_code, a.status_type,
row_number() over (partition by a.id order by start_date) rn
FROM mytbl a
WHERE NOT EXISTS
(SELECT 1
FROM mytbl b
WHERE b.status_type = 'INACTIVE'
AND a.id = b.id)) a
WHERE a.rn = 1
UNION ALL
SELECT a.id, a.start_date, a.end_date, a.action_code, a.status_type
FROM
(SELECT a.id, a.start_date, a.end_date, a.action_code, a.status_type,
row_number() over (partition by a.id order by start_date) rn
FROM mytbl a
WHERE EXISTS
(SELECT 1
FROM mytbl b
WHERE b.status_type = 'INACTIVE'
AND a.id = b.id
AND a.start_date > b.start_date)) a
WHERE a.rn = 1
Upvotes: 1
Reputation: 35920
You can achieve this using multiple subqueries and analytical function
:
SELECT T.* FROM
(SELECT T.*,
ROW_NUMBER()
OVER (partition by employee_number ORDER BY START_DATE)AS RN
FROM
(SELECT T.*
FROM
(Select t.*,
max(case when status_type='INACTIVE' THEN start_date END)
over (partition by employee_number) AS MAX_INACTIVE_DATE
FROM ASG_TABLE t) t
WHERE COALESCE(MAX_INACTIVE_DATE, START_DATE) >= START_DATE
AND STATUS_TYPE='ACTIVE') t ) t
WHERE RN = 1;
Cheers!!
Upvotes: 0
Reputation: 7386
try this: (this answer is for the initial version of the question you are asking.)
WITH DATASET AS (
SELECT 1 ASG_NUMBER,TO_DATE('20180101','yyyymmdd') EFFECTIVE_START_DATE,'ACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 1 ASG_NUMBER,TO_DATE('20180121','yyyymmdd') EFFECTIVE_START_DATE,'ACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 1 ASG_NUMBER,TO_DATE('20180219','yyyymmdd') EFFECTIVE_START_DATE,'INACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 1 ASG_NUMBER,TO_DATE('20180701','yyyymmdd') EFFECTIVE_START_DATE,'ACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 1 ASG_NUMBER,TO_DATE('20190101','yyyymmdd') EFFECTIVE_START_DATE,'ACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 2 ASG_NUMBER,TO_DATE('20190201','yyyymmdd') EFFECTIVE_START_DATE,'ACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 2 ASG_NUMBER,TO_DATE('20190402','yyyymmdd') EFFECTIVE_START_DATE,'ACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 3 ASG_NUMBER,TO_DATE('20190301','yyyymmdd') EFFECTIVE_START_DATE,'ACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 3 ASG_NUMBER,TO_DATE('20190402','yyyymmdd') EFFECTIVE_START_DATE,'INACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 4 ASG_NUMBER,TO_DATE('20180801','yyyymmdd') EFFECTIVE_START_DATE,'ACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 4 ASG_NUMBER,TO_DATE('20180821','yyyymmdd') EFFECTIVE_START_DATE,'INACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 4 ASG_NUMBER,TO_DATE('20180821','yyyymmdd') EFFECTIVE_START_DATE,'ACTIVE'STATUS_TYPE FROM DUAL UNION ALL
SELECT 4 ASG_NUMBER,TO_DATE('20181101','yyyymmdd') EFFECTIVE_START_DATE,'ACTIVE'STATUS_TYPE FROM DUAL
), SUB1 AS(
SELECT
ASG_NUMBER,
MAX (STATUS_TYPE) KEEP (DENSE_RANK FIRST ORDER BY EFFECTIVE_START_DATE DESC) STATUS_TYPE,
MAX (CASE WHEN STATUS_TYPE ='INACTIVE' THEN EFFECTIVE_START_DATE ELSE NULL END)INACTIVE_DATE
FROM DATASET
GROUP BY ASG_NUMBER
),INACTIVE_2_ACTIVE AS (
SELECT
DATASET.ASG_NUMBER,
MIN(EFFECTIVE_START_DATE) EFFECTIVE_START_DATE
FROM DATASET,SUB1
WHERE 1=1
AND DATASET.ASG_NUMBER=SUB1.ASG_NUMBER
AND DATASET.EFFECTIVE_START_DATE>=SUB1.INACTIVE_DATE
AND DATASET.STATUS_TYPE='ACTIVE'
GROUP BY DATASET.ASG_NUMBER
),JUST_ACTIVE AS (
SELECT
DATASET.ASG_NUMBER,
MIN(EFFECTIVE_START_DATE) EFFECTIVE_START_DATE
FROM
DATASET,SUB1
WHERE 1=1
AND DATASET.ASG_NUMBER=SUB1.ASG_NUMBER
AND SUB1.INACTIVE_DATE IS NULL
AND DATASET.STATUS_TYPE='ACTIVE'
GROUP BY DATASET.ASG_NUMBER
),LASTVALUE_INACTIVE AS
(
SELECT
DATASET.ASG_NUMBER,
MIN(EFFECTIVE_START_DATE) EFFECTIVE_START_DATE
FROM
DATASET,SUB1
WHERE 1=1
AND DATASET.ASG_NUMBER=SUB1.ASG_NUMBER
AND DATASET.EFFECTIVE_START_DATE<=SUB1.INACTIVE_DATE
AND DATASET.STATUS_TYPE='ACTIVE'
AND SUB1.STATUS_TYPE='INACTIVE'
GROUP BY DATASET.ASG_NUMBER
)
SELECT *
FROM
INACTIVE_2_ACTIVE
UNION
SELECT *
FROM
JUST_ACTIVE
UNION
SELECT *
FROM
LASTVALUE_INACTIVE
Upvotes: 0