我有一个员工历史记录表,其中包含状态日期,状态和员工ID。状态日期不是相同的日期,有时可能要持续几个月才能更新。我需要创建一个报告,以每月创建雇员状态的每月快照。
当前,我选择的是sysdate月份开始之前的最大状态日期,并通过一次从查询中减去一个月来重复此查询,然后进行合并以合并所有日期。
SELECT id,
status_date,
status,
(trunc(sysdate, 'month')) AS Activity_Month
FROM empl_hist as e1 join
(SELECT id, max(status_date) AS max_date, status_date FROM empl_hist
WHERE status_date <= (trunc(sysdate, 'month')) e2
on e1.id = e2.id and e1.status_date = e2.status_date
UNION ALL
SELECT id,
status_date,
status,
(trunc(add_months(sysdate,-1), 'month')) AS Activity_Month,
FROM empl_hist as e1 join
(SELECT id, max(status_date) AS max_date, status_date FROM empl_hist
WHERE status_date <= (trunc(add_months(sysdate,-1), 'month')) e2
on e1.id = e2.id and e1.status_date = e2.status_date
我需要过去24个月的这份报告,而且似乎应该有比23个联盟更好的方法。
答案 0 :(得分:1)
您可以使用递归查询来执行此操作以生成报告月份,然后将其加入到empl_hist表中并使用聚合函数来获得所需的结果:
WITH REPORT(ACTIVITY_MONTH) AS (
SELECT CAST(ADD_MONTHS(TRUNC(SYSDATE,'month'),-24) AS DATE)
FROM DUAL
UNION ALL
SELECT CAST(ADD_MONTHS(ACTIVITY_MONTH,1) AS DATE)
FROM REPORT
WHERE ADD_MONTHS(ACTIVITY_MONTH,1) < SYSDATE
)
SELECT eh.id
, max(eh.status_date) status_Date
, max(eh.status) keep (dense_rank first order by status_date desc) status
, r.activity_month
FROM REPORT r
JOIN EMPL_HIST EH
ON EH.STATUS_DATE <= r.ACTIVITY_MONTH
group by eh.id, r.activity_month
答案 1 :(得分:1)
如果在第一步中计算有效期,即最后一天(包括该天),则可以使与 calendar 表(包含24个报告月的表)的联接更有效。状态为有效-status_date_to
。
如果status_date
被截断(即没有时间),则建议的计算有效。
如果有时间因素,请使用status_date - interval '1' second
代替status_date - 1
。
比起您,您只能将{em>匹配中与reporing_month相匹配的EPML_HISTORY
c.reporting_month between h.status_date and h.status_date_to
另外请注意,您应该重新查看使用WITH calendar AS (
SELECT trunc(add_months(sysdate, 1-level), 'MM') reporting_month
FROM dual
CONNECT BY level <= 24
), hist as (
SELECT id,
status_date,
nvl(lead(status_date-1) over (partition by id order by status_date),add_months(trunc(sysdate, 'MM'),1)) as status_date_to,
status
from empl_hist)
select REPORTING_MONTH, ID, STATUS
from calendar c
join hist h on c.reporting_month between h.status_date and h.status_date_to
order by id, reporting_month;
REPORTING_MONTH ID STATUS
------------------- ---------- ----------
01.05.2018 00:00:00 1 active
01.06.2018 00:00:00 1 active
01.07.2018 00:00:00 1 active
01.08.2018 00:00:00 1 active
01.09.2018 00:00:00 1 deactive
01.10.2018 00:00:00 1 deactive
01.11.2018 00:00:00 1 deactive
01.12.2018 00:00:00 1 deactive
01.01.2019 00:00:00 1 active
01.08.2018 00:00:00 2 active
01.09.2018 00:00:00 2 active
01.10.2018 00:00:00 2 active
01.11.2018 00:00:00 2 deactive
01.12.2018 00:00:00 2 deactive
01.01.2019 00:00:00 2 deactive
01.01.2019 00:00:00 4 active
指定报告月份的逻辑。在status_date <= (trunc(sysdate, 'month')
下面的示例数据中,由于id=3
在当月5号被激活,因此被忽略,但是报告id=4
是因为它在当月1号处于活动状态。
样本数据
drop table empl_hist;
create table empl_hist(
id number,
status_date date,
status varchar2(10));
insert into empl_hist values(1,DATE'2018-05-01','active');
insert into empl_hist values(1,DATE'2018-08-05','deactive');
insert into empl_hist values(1,DATE'2018-12-05','active');
insert into empl_hist values(2,DATE'2018-07-05','active');
insert into empl_hist values(2,DATE'2018-10-05','deactive');
insert into empl_hist values(3,DATE'2019-01-05','active');
insert into empl_hist values(4,DATE'2019-01-01','active');
答案 2 :(得分:0)
您可以使用子查询生成24个月的列表并将其加入。然后,我将使用row_number
来确定窗口中最近的一条记录,以避免发生自我联接:
SELECT id, status_date, status, Activity_Month
FROM (
SELECT e.*,
m.Activity_Month,
row_number() OVER (PARTITION BY m.Activity_Month
ORDER BY e.status_date DESC) rn
FROM (
SELECT trunc(add_months(sysdate, 1-level), 'month') Activity_Month
FROM dual
CONNECT BY level <= 24
) m
INNER JOIN empl_hist e
ON e.status_date <= m.Activity_Month
) base
WHERE rn = 1
ORDER BY Activity_Month