2013-05-08 105 views
4

我有一張表,其中列出了員工成爲活動/非活動日期的列表,並且我想要計算員工在特定日期範圍內處於活動狀態的週數。SQL查找僱員在兩個日期之間活躍的週數

所以表(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月11至31日,DEC-數量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數據庫11g企業版發佈11.2.0.3.0 - 64位生產

+0

你能更好地解釋你的需求嗎?您的表格中可以有多個條目嗎?我的意思是,如果員工是活躍的,每個星期你都會儲存?或者每個月? – Madthew 2013-05-08 17:29:41

+0

因此,每當員工被聘用或終止時,表格都會更新。在這種情況下,員工被聘用01年7月1日,所以他們的HR_STATUS是A(ctive)。然後他們被終止01年9月11日,所以他們的HR_STATUS是我(無效)。然後他們在1月1日至12日被重新聘用,12月1日再次被終止,然後在12月9日重新入職,直到今天仍然活躍。這是一個極端的例子,但是顯示了員工在激活狀態和非激活狀態之間彈跳如何使查詢更加困難。 – BarrettNashville 2013-05-08 17:33:39

+0

在你的例子中,你試圖把日期推到星期日。假設僱員在本週五(5/10/2013)聘用,並於下週的週一(2013年5月13日)結束。他們的「週數」可以是0(3天,四捨五入= 0周),1(3天=一週的一部分)或2(兩週內有效)。你想報告哪個? – 2013-05-08 17:38:14

回答

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; 

的​​3210功能會搶在事件系統日期無法找到匹配I記錄(員工是最新的)。如果這是你的規格,你可以替代年底。

請注意,我沒有進行任何嚴格的測試以查看您的條目是否已訂購A/I/A/I等,因此如果您知道數據需要,可能需要添加該性質的檢查。

隨意玩這個在SQL Fiddle

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 

爲第三個演出有一個活動的日期,但沒有停止日期,因此在ROW_NUMBER排序和左邊的NULLS LAST兩個子查詢之間的連接。

我已經在這裏使用了「天/ 7」數學;當您從客戶那裏收到回覆時,您可以替代您所需要的。請注意,如果沒有相應的非活動日期,查詢將使用當前日期。

有這個here的SQLFiddle。

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 

內查詢會拉從表中的僱員和人力資源狀況的信息,並使用effdt列的開始日期和使用LEAD分析函數結束日期從表中獲取下一個effdt日期值,該值指示下一個狀態的開始,因此將是當前行的end_date。如果LEAD函數返回NULL,我們爲它指定完成日期(2012年12月31日),你想要。那麼他出來的聲明只是將結果集限制在具有活動HR狀態的記錄中並計算週數。

相關問題