Reputation: 117
I have the following table structure:
NAME DEPT IN_DEPT OUT_DEPT
J. Smith Fin/Team1 2014-05-10 NULL
J. Smith Fin/Team2 2012-07-08 2014-05-09
J. Smith Fin/Team4 2011-10-11 2012-07-07
I. Ivanov Acc/Team2 2015-03-05 NULL
I. Ivanov Fin/Team2 2011-02-08 2015-03-04
I intend to do a timeline of the Finance Dept mobility (external - not inside teams). So, i already did a SELECT MIN(IN_DEPT), which is quite easy, and i need now to find the MAX(OUT_DEPT) to UNION findings.
But in that case, J. Smith is still in the Finance dept., so the MAX date is not fine.
I'm having trouble to make this query, when if there are a NULL value in the OUT_DEPT and the DEPT value begins with 'Fin', it throw out every other findings of the NAME.
The goal table result might be like this:
NAME DATE ACTION
I. Ivanov 2015-03-04 OUT
J. Smith 2011-10-11 IN
I. Ivanov 2011-02-08 IN
Any help appreciated. Thanks.
Upvotes: 1
Views: 96
Reputation: 335
This should work. First select the minimum of in dates. Next those dates are unioned with the maximum of out dates, where only people are regarded who have left the department. This means there must not exist a name in a department without an OUT_DEPT.
SELECT NAME, MIN(IN_DEPT) DATE, 'IN' ACTION
FROM DEPARTMENT
WHERE DEPT LIKE 'Fin/%'
GROUP BY NAME
UNION ALL
SELECT D0.NAME, MAX(D0.OUT_DEPT) DATE, 'OUT' ACTION
FROM DEPARTMENT D0
WHERE DEPT LIKE 'Fin/%'
AND NOT EXISTS (
SELECT 1
FROM DEPARTMENT D1
WHERE D1.NAME = D0.NAME
AND D1.DEPT LIKE 'Fin/%'
AND D1.OUT_DEPT IS NULL )
GROUP BY NAME
However, condition with NOT EXISTS
looks better if you split department and team or select only records from finance department in a CTE.
WITH DEPARTMENT_FIN (NAME, IN_DEPT, OUT_DEPT) AS (
SELECT NAME
,IN_DEPT
,OUT_DEPT
FROM DEPARTMENT
WHERE DEPT LIKE 'Fin%'
)
SELECT NAME, MIN(IN_DEPT) DATE, 'IN' ACTION
FROM DEPARTMENT_FIN
GROUP BY NAME
UNION ALL
SELECT D0.NAME, MAX(D0.OUT_DEPT) DATE, 'OUT' ACTION
FROM DEPARTMENT_FIN D0
WHERE NOT EXISTS (
SELECT 1
FROM DEPARTMENT_FIN D1
WHERE D1.NAME = D0.NAME
AND D1.OUT_DEPT IS NULL )
GROUP BY NAME
Upvotes: 0
Reputation: 1269933
You need to identify when people enter finance and leave. This is tricky. Here is one method using lag()
and lead()
:
with cte as (
select t.*
from (select t.*,
lag(out_dept) over (partition by name order by in_dept) as prev_out,
lead(in_dept) over (partition by name order by in_dept) as next_in
from t
where dept like 'Fin%'
)
select name, in_dept, 'IN'
from t
where prev_out is null or prev_out <> in_dept - 1 day
union all
select name, out_dept, 'OUT'
from t
where next_in is null or next_in <> out_dept + 1 day;
Upvotes: 1