You haven't given me an answer on higher priorities overriding validity of lower priorities, so I did both examples. In this first example, higher priority events "delete" lower priority events, consistent with Your expected output.
WITH source (d_date, emp_id, dept_id, course_id, f_priority, s_priority, deleted, d_timestamp) AS
( VALUES ('20190419', 'E1', 'D1', 'C1', 'Low', 2, 0, '2019-04-19 12:10:18'),
('20190521', 'E1', 'D1', 'C2', 'Medium', 2, 0, '2019-05-21 12:10:18'),
('20190521', 'E1', 'D1', 'C3', 'High', 4, 0, '2019-05-21 14:10:18'),
('20190521', 'E1', 'D1', 'C4', 'High', 4, 0, '2019-05-21 14:11:18'),
('20190621', 'E1', 'D1', 'C3', 'High', 4, 1, '2019-06-21 15:10:18'),
('20190621', 'E1', 'D1', 'C5', 'High', 4, 0, '2019-06-21 16:10:18'),
('20191021', 'E1', 'D1', 'C6', 'High', 8, 0, '2019-06-21 16:10:18'),
('20200121', 'E1', 'D1', 'C7', 'Critical', 4, 0, '2019-05-21 14:10:18'),
('20200121', 'E1', 'D1', 'C8', 'Critical', 4, 0, '2019-05-21 14:11:18'),
('20190419', 'E2', NULL, 'C1', 'Low', 2, 0, '2019-04-19 12:10:18'),
('20190521', 'E2', NULL, 'C2', 'Medium', 2, 0, '2019-05-21 12:10:18'),
('20190521', 'E2', NULL, 'C3', 'High', 4, 0, '2019-05-21 14:10:18'),
('20190521', 'E2', NULL, 'C4', 'High', 4, 0, '2019-05-21 14:11:18'),
('20190531', 'E2', NULL, 'C2', 'Medium', 2, 1, '2019-05-31 15:01:18'),
('20190621', 'E2', 'D2', 'C3', 'High', 4, 0, '2019-06-21 15:10:18'),
('20190621', 'E2', 'D2', 'C5', 'High', 6, 0, '2019-06-21 16:10:18'),
('20190721', 'E2', 'D2', 'C5', 'High', 6, 1, '2019-06-21 15:10:18'),
('20191021', 'E2', 'D2', 'C7', 'Low', 8, 0, '2019-06-21 16:10:18')
), max_priorities (emp_id, dept_id, d_date, course_id, f_priority, s_priority, deleted, fs_ord_priority, max_fs_ord_priority) AS
( SELECT emp_id, dept_id, d_date, course_id, s.f_priority, s_priority, deleted, def.f_ord_priority*10+s_priority,
MAX(def.f_ord_priority*10+s_priority) OVER (PARTITION BY emp_id, dept_id, d_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM source s
INNER JOIN (VALUES ('Low', 1), ('Medium', 2), ('High', 3), ('Critical', 4)) AS def(f_priority, f_ord_priority) ON s.f_priority = def.f_priority
), filtered_priorities (emp_id, dept_id, d_date, course_id, deleted, fs_ord_priority, entry_ord, entry_count, date_ord) AS
( SELECT emp_id, dept_id, d_date, course_id, deleted, fs_ord_priority,
ROWNUMBER() OVER (PARTITION BY emp_id, dept_id ORDER BY d_date, course_id),
COUNT(*) OVER (PARTITION BY emp_id, dept_id),
COUNT(*) OVER (PARTITION BY emp_id, dept_id ORDER BY d_date)
FROM max_priorities
WHERE max_fs_ord_priority = fs_ord_priority
)
, recursive_courses (emp_id, dept_id, d_date, course_dtl, current_fs_ord_priority, entry_ord, entry_count, date_ord) AS
( SELECT emp_id, dept_id, d_date, CAST(',' || course_id AS VARCHAR(100)), fs_ord_priority, entry_ord, entry_count, date_ord
FROM filtered_priorities
WHERE entry_ord = 1
UNION ALL
SELECT n.emp_id, n.dept_id, n.d_date,
CASE WHEN o.current_fs_ord_priority < n.fs_ord_priority THEN ',' || n.course_id
WHEN o.current_fs_ord_priority > n.fs_ord_priority THEN o.course_dtl
WHEN o.current_fs_ord_priority = n.fs_ord_priority AND n.deleted = 0 THEN o.course_dtl || ',' || n.course_id
ELSE INSERT(o.course_dtl, LOCATE(','||n.course_id||',', o.course_dtl||','), LENGTH(','||n.course_id), '')
END,
CASE WHEN o.current_fs_ord_priority < n.fs_ord_priority THEN n.fs_ord_priority
WHEN o.current_fs_ord_priority = n.fs_ord_priority AND n.deleted = 1 AND LOCATE(',', o.course_dtl, 2) = 0 THEN -1
ELSE o.current_fs_ord_priority
END,
CASE WHEN o.current_fs_ord_priority > n.fs_ord_priority THEN -1 ELSE n.entry_ord END,
n.entry_count, n.date_ord
FROM recursive_courses o, filtered_priorities n
WHERE (o.emp_id, COALESCE(o.dept_id, 'N/A'), o.entry_ord + 1) = (n.emp_id, COALESCE(n.dept_id, 'N/A'), n.entry_ord)
AND n.entry_ord <= o.entry_count
)
SELECT emp_id, dept_id, CASE WHEN course_dtl != '' THEN SUBSTR(course_dtl, 2) END AS course_dtl,
d_date AS s_date,
COALESCE( INSERT(INSERT(CHAR(
DATE(INSERT(INSERT(LEAD(d_date) OVER (PARTITION BY emp_id, dept_id ORDER BY d_date), 5, 0, '-'), 8, 0, '-')) - 1 DAY
), 5, 1, ''), 7, 1, '')
, '99991231') AS e_date
FROM recursive_courses
WHERE entry_ord = date_ord
ORDER BY emp_id, COALESCE(dept_id, ''), d_date
;
EMP_ID | DEPT_ID | COURSE_DTL | S_DATE | E_DATE
-----: | ------: | ---------: | -------: | -------:
E1 | D1 | C1 | 20190419 | 20190520
E1 | D1 | C3,C4 | 20190521 | 20190620
E1 | D1 | C4,C5 | 20190621 | 20191020
E1 | D1 | C6 | 20191021 | 20200120
E1 | D1 | C7,C8 | 20200121 | 99991231
E2 | null | C1 | 20190419 | 20190520
E2 | null | C3,C4 | 20190521 | 99991231
E2 | D2 | C5 | 20190621 | 20190720
E2 | D2 | null | 20190721 | 20191020
E2 | D2 | C7 | 20191021 | 99991231
db<>fiddle here
But I had to do a recursive CTE.
Commentary to individual CTEs:
- max_priorities: find the maximum priority in a day (per emp_id and dept_id) as a numerical value (f_priority and s_priority combined); "Delete" rows with lower priority don't have to be considered, as higher priority takes precedence,
- filtered_priorities: take only the highest priority per day (and emp_id and dept_id, of course...), calculate entry order, entry/date order and count (so as to identify the last entry in a day and the last entry per emp_id and dept_id),
- recursive_courses: take one row at a time by their order, according to priority values, deletes etc. calculate its courses (always with a leading comma for practical reasons!; if we came upon a removal of the last active course, priority drops to -1,
- last INSERTS are there just to convert the next d_date (YYYYMMDD) into a real DATE, find the previous day and convert it back to YYYYMMDD.
With the second alternative, if all courses have to be explicitly deleted to mark an end, I chose a different approach: I tried to find out for each and every day, which courses are valid. I won't comment it further, as I am not sure, if You are interested in this answer too. (It differs from Your "expected output".)
WITH source (d_date, emp_id, dept_id, course_id, f_priority, s_priority, deleted, d_timestamp) AS
( VALUES ('20190419', 'E1', 'D1', 'C1', 'Low', 2, 0, '2019-04-19 12:10:18'),
('20190521', 'E1', 'D1', 'C2', 'Medium', 2, 0, '2019-05-21 12:10:18'),
('20190521', 'E1', 'D1', 'C3', 'High', 4, 0, '2019-05-21 14:10:18'),
('20190521', 'E1', 'D1', 'C4', 'High', 4, 0, '2019-05-21 14:11:18'),
('20190621', 'E1', 'D1', 'C3', 'High', 4, 1, '2019-06-21 15:10:18'),
('20190621', 'E1', 'D1', 'C5', 'High', 4, 0, '2019-06-21 16:10:18'),
('20191021', 'E1', 'D1', 'C6', 'High', 8, 0, '2019-06-21 16:10:18'),
('20200121', 'E1', 'D1', 'C7', 'Critical', 4, 0, '2019-05-21 14:10:18'),
('20200121', 'E1', 'D1', 'C8', 'Critical', 4, 0, '2019-05-21 14:11:18'),
('20190419', 'E2', NULL, 'C1', 'Low', 2, 0, '2019-04-19 12:10:18'),
('20190521', 'E2', NULL, 'C2', 'Medium', 2, 0, '2019-05-21 12:10:18'),
('20190521', 'E2', NULL, 'C3', 'High', 4, 0, '2019-05-21 14:10:18'),
('20190521', 'E2', NULL, 'C4', 'High', 4, 0, '2019-05-21 14:11:18'),
('20190531', 'E2', NULL, 'C2', 'Medium', 2, 1, '2019-05-31 15:01:18'),
('20190621', 'E2', 'D2', 'C3', 'High', 4, 0, '2019-06-21 15:10:18'),
('20190621', 'E2', 'D2', 'C5', 'High', 6, 0, '2019-06-21 16:10:18'),
('20190721', 'E2', 'D2', 'C5', 'High', 6, 1, '2019-06-21 15:10:18'),
('20191021', 'E2', 'D2', 'C7', 'Low', 8, 0, '2019-06-21 16:10:18')
), all_dates (d_date) AS
( SELECT INSERT(INSERT(CHAR(min_dt+(a+b+c) DAYS),5,1,''),7,1,'')
FROM ( SELECT DATE(INSERT(INSERT(MIN(d_date),5,0,'-'),8,0,'-')), DATE(INSERT(INSERT(MAX(d_date),5,0,'-'),8,0,'-')) FROM SOURCE ) AS def(min_dt, max_dt)
CROSS JOIN (VALUES 0,1,2,3,4,5,6,7,8,9) AS aa(a)
CROSS JOIN (VALUES 00,10,20,30,40,50,60,70,80,90) AS bb(b)
CROSS JOIN (VALUES 000,100,200,300,400,500,600,700,800,900) AS cc(c)
WHERE min_dt + (a+b+c) DAYS <= max_dt
UNION ALL
VALUES '99991231'
), all_dates_and_emp_dept_courses (emp_id, dept_id, course_id, d_date, f_priority, s_priority) AS
( SELECT def.emp_id, def.dept_id, def.course_id, d.d_date,
NULLIF(LAST_VALUE(CASE WHEN s.deleted=1 THEN 'DELETED' ELSE s.f_priority END, 'IGNORE NULLS') OVER (PARTITION BY def.emp_id, def.dept_id, def.course_id ORDER BY d.d_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), 'DELETED'),
NULLIF(LAST_VALUE(CASE WHEN s.deleted=1 THEN -100 ELSE s.s_priority END, 'IGNORE NULLS') OVER (PARTITION BY def.emp_id, def.dept_id, def.course_id ORDER BY d.d_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), -100)
FROM (SELECT emp_id, dept_id, course_id,
MIN(MIN(d_date))OVER(PARTITION BY emp_id, dept_id ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
MAX(MAX(d_date))OVER(PARTITION BY emp_id, dept_id ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM source
GROUP BY emp_id, dept_id, course_id
) AS def (emp_id, dept_id, course_id, min_d_date, max_d_date)
INNER JOIN all_dates d ON d.d_date BETWEEN def.min_d_date AND def.max_d_date OR d.d_date = '99991231'
LEFT JOIN source s ON (def.emp_id, COALESCE(def.dept_id,'N/A'), def.course_id, d.d_date) = (s.emp_id, COALESCE(s.dept_id,'N/A'), s.course_id, s.d_date)
), all_dates_and_emp_dept_priorities (emp_id, dept_id, d_date, f_priority, s_priority, max_fs_priority, course_dtl, count_changes) AS
( SELECT emp_id, dept_id, d_date,
f_priority, s_priority, LAST_VALUE(f_priority||'/'||CHAR(s_priority)) OVER (PARTITION BY emp_id, dept_id, d_date ORDER BY DECODE(f_priority, 'Low', 1, 'Medium', 2, 'High', 3, 'Critical', 4) NULLS FIRST, s_priority NULLS FIRST ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
LISTAGG(course_id, ','),
SUM(CASE WHEN COALESCE(LAG(LISTAGG(course_id, ',')) OVER (PARTITION BY emp_id, dept_id, f_priority, s_priority ORDER BY d_date),'N/A')=COALESCE(LISTAGG(course_id, ','),'N/A') THEN 0 ELSE 1 END) OVER (PARTITION BY emp_id, dept_id, f_priority, s_priority ORDER BY d_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM all_dates_and_emp_dept_courses
GROUP BY emp_id, dept_id, d_date, f_priority, s_priority
)
SELECT DISTINCT emp_id, dept_id, course_dtl,
MIN(d_date) OVER (PARTITION BY emp_id, dept_id, course_dtl ORDER BY count_changes RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING),
MAX(d_date) OVER (PARTITION BY emp_id, dept_id, course_dtl ORDER BY count_changes RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING)
FROM all_dates_and_emp_dept_priorities
WHERE COALESCE(f_priority||'/'||CHAR(s_priority),'N/A')=COALESCE(max_fs_priority,'N/A')
ORDER BY emp_id, dept_id, 4
;
EMP_ID | DEPT_ID | COURSE_DTL | 4 | 5
-----: | ------: | ---------: | -------: | -------:
E1 | D1 | C1 | 20190419 | 20190520
E1 | D1 | C3,C4 | 20190521 | 20190620
E1 | D1 | C4,C5 | 20190621 | 20191020
E1 | D1 | C6 | 20191021 | 20200120
E1 | D1 | C7,C8 | 20200121 | 99991231
E2 | D2 | C5 | 20190621 | 20190720
E2 | D2 | C3 | 20190721 | 99991231
E2 | null | C1 | 20190419 | 20190520
E2 | null | C3,C4 | 20190521 | 99991231
db<>fiddle here