我有一张表格,其中列出了员工成为主动/非活动状态的日期,我想计算员工在特定日期范围内活跃的周数。
因此表(ps_job)将具有如下值:
EMPLID EFFDT HR_STATUS
------ ----- ------
1000 01-Jul-11 A
1000 01-Sep-11 I
1000 01-Jan-12 A
1000 01-Mar-12 I
1000 01-Sep-12 A
查询需要向我显示这个emplid在01年7月11日到31日 - 12月12日期间的活动周数。
所需的结果集将是:
EMPLID WEEKS_ACTIVE
------ ------------
1000 35
我通过添加以下SQL的结果获得了数字35:
SELECT (NEXT_DAY('01-Sep-11','SUNDAY') - NEXT_DAY('01-Jul-11','SUNDAY'))/7 WEEKS_ACTIVE FROM DUAL;
SELECT (NEXT_DAY('01-Mar-12','SUNDAY') - NEXT_DAY('01-Jan-12','SUNDAY'))/7 WEEKS_ACTIVE FROM DUAL;
SELECT (NEXT_DAY('31-Dec-12','SUNDAY') - NEXT_DAY('01-Sep-12','SUNDAY'))/7 WEEKS_ACTIVE FROM DUAL;
问题是我似乎无法弄清楚如何创建单个查询语句,该语句将遍历特定日期范围内的每个员工的所有行,并且只返回每个emplid以及它们处于活动状态的周数。我更喜欢使用基本的SQL而不是PL / SQL,以便我可以将其传输到可以由用户运行的PeopleSoft查询,但是如果需要,我愿意为使用Oracle SQL Developer的用户运行它。
数据库:Oracle Database 11g企业版11.2.0.3.0版 - 64位生产
答案 0 :(得分:1)
如果客户只想粗略估计,我会从每个限期的天数开始,除以7并四舍五入。
诀窍是将活动日期与其相应的非活动日期对齐,我认为这样做的最佳方式是分别选择活动日期和非活动日期,按日期排名,然后将它们重新加入EmplID
和等级。 ROW_NUMBER()
分析函数是在这种情况下排名的最佳方式:
WITH
EmpActive AS (
SELECT
EmplID,
EffDt,
ROW_NUMBER() OVER (PARTITION BY EmplID ORDER BY EffDt NULLS LAST) DtRank
FROM ps_job
WHERE HR_Status = 'A'
),
EmpInactive AS (
SELECT
EmplID,
EffDt,
ROW_NUMBER() OVER (PARTITION BY EmplID ORDER BY EffDt NULLS LAST) DtRank
FROM ps_job
WHERE HR_Status = 'I'
)
SELECT
EmpActive.EmplID,
EmpActive.EffDt AS ActiveDate,
EmpInactive.EffDt AS InactiveDate,
ROUND((NVL(EmpInactive.EffDt, TRUNC(SYSDATE)) - EmpActive.EffDt) / 7) AS WeeksActive
FROM EmpActive
LEFT JOIN EmpInactive ON
EmpActive.EmplID = EmpInactive.EmplID AND
EmpActive.DtRank = EmpInactive.DtRank
EmplID = 1000
的第三个演出有一个有效日期但没有非活动日期,因此NULLS LAST
排序中的ROW_NUMBER
和两个子查询之间的左连接。
我在这里使用了“days / 7”数学;当您收到客户的回复时,您可以替换您需要的东西。请注意,如果没有相应的非活动日期,则查询将使用当前日期。
这是here的SQLFiddle。
答案 1 :(得分:1)
以下内容适用于您要执行的操作。我必须在NVL声明中硬编码结束日期
SELECT emplid,
hr_status,
ROUND(SUM(end_date - start_date)/7) num_weeks
FROM (SELECT emplid,
hr_status,
effdt start_date,
NVL(LEAD(effdt) OVER (PARTITION BY emplid ORDER BY effdt),
TO_DATE('12312012','MMDDYYYY')) end_date
FROM ps_job
)
WHERE hr_status = 'A'
GROUP BY emplid,
hr_status
ORDER BY emplid
内部查询将从表中提取员工和HR状态信息,并使用effdt列作为开始日期,并使用LEAD分析函数从表中获取下一个effdt日期值,这表示下一个的开始status和so将是当前行的end_date。如果LEAD函数返回NULL,我们为它指定您想要的完成日期(12/31/2012)。然后他将语句结果限制为具有活动人力资源状态的记录并计算周数。
答案 2 :(得分:1)
这里我在子查询中使用lead
来获取下一个日期,然后在外部查询中求和间隔:
with q as (
select EMPLID, EFFDT, HR_STATUS
, lead (EFFDT, 1) over (partition by EMPLID order by EFFDT) as NEXT_EFFDT
from ps_job
order by EMPLID, EFFDT
)
select EMPLID
, trunc(sum((trunc(coalesce(NEXT_EFFDT, current_timestamp)) - trunc(EFFDT)) / 7)) as WEEKS_ACTIVE
from q
where HR_STATUS = 'A'
group by EMPLID;
如果找不到匹配的coalesce
记录(员工是最新的),I
函数将获取系统日期。如果这是您的规格,您可以替换年底。
请注意,我没有进行任何严格的测试,以确保您的参赛作品是订购的A / I / A / I等,因此如果您知道您的数据需要,您可能需要添加这种性质的支票。
随意在SQL Fiddle播放。