簡體   English   中英

SQL 計算滾動周期內周轉率的查詢

[英]SQL Query for calculating Turnover Rate over rolling period

編輯:我完全重新編輯了這個問題。 希望在評論部分提供所需的信息。 這是我第一次在這里發布問題,所以我為錯過和忘記包含這么多重要細節而道歉。 我幾乎問了另一個關於如何格式化這個權利的問題......

表:

TABLE [Facility]
[ID]             [int] IDENTITY(1,1) NOT NULL,
[Site]           [nvarchar](255) NULL,
[ContractID]     [int] NULL,


TABLE [Employees]

[ID]             [int] IDENTITY(1,1) NOT NULL,
[Payroll]        [nvarchar](6) NULL
[LastName]       [nvarchar](50) NULL,
[HomeStation]    [nvarchar](50) NULL,
[WorkLocation]   [nvarchar](50) NULL,
[DateOfHire]     [datetime] NULL,
[TermDate]       [datetime] NULL,
[Status]         [nvarchar](10) NULL,
[HomeStationID]  [int] NULL,
[ContractID]     [ContractID] [int] NULL,

如果我 select 來自每個表,則示例 output 如下:

設施:

ID 地點 合同編號
1 盧卡斯營 8
2 六十堡 8
3 雙重麻煩 8
4 檸檬營 8
5 蘋果樹營地 8
6 堡壘示例 8
8 基地醫生 8
9 實驗室測試 16 9
10 麥當勞 9
11 麥克斯廷基 9
13 內布拉斯加州拼箱 9
14 營地結構 9
16 七十一堡 9
17 羅伯特堡K 9
18 騎吟游詩人 9
19 營地空閑用戶 9
20 漢堡王 9

雇員:

ID 工資單 家庭站 工作地點 雇用日期 學期日期 地位 主站 ID 合同編號
1 000001 卡特萊特 麥克斯廷基 麥克斯廷基 1999-12-27 00:00:00.000 2017-01-03 00:00:00.000 不活躍 11 9
4 000002 蘭伯特 內布拉斯加州拼箱 內布拉斯加州拼箱 2000-01-14 00:00:00.000 1900-01-01 00:00:00.000 積極的 13 9
5 000003 桑托斯 羅伯特堡K 羅伯特堡K 2001-08-03 00:00:00.000 1900-01-01 00:00:00.000 積極的 17 9
6 000004 派克 漢堡王 漢堡王 2000-04-07 00:00:00.000 1900-01-01 00:00:00.000 積極的 8 9
9 000007 斯萊登 實驗室測試 16 實驗室測試 16 2000-04-28 00:00:00.000 2017-03-10 00:00:00.000 不活躍 9 8
10 000008 羅薩多 營地結構 營地結構 2013-07-01 00:00:00.000 2017-07-01 00:00:00.000 不活躍 14 1
11 000009 騎士 內布拉斯加州拼箱 內布拉斯加州拼箱 2016-02-28 00:00:00.000 2019-04-08 00:00:00.000 不活躍 13 3
12 000010 佩納 麥當勞 麥當勞 2000-06-12 00:00:00.000 2013-12-31 00:00:00.000 不活躍 10 9
13 000011 塞繆爾 騎吟游詩人 騎吟游詩人 2008-08-07 00:00:00.000 2015-10-29 00:00:00.000 不活躍 18 9
14 000012 櫻桃 七十一堡 七十一堡 2013-07-01 00:00:00.000 2013-07-30 00:00:00.000 不活躍 16 9
15 000013 瓊斯 騎吟游詩人 騎吟游詩人 2000-08-29 00:00:00.000 2013-01-07 00:00:00.000 不活躍 18 9
16 000014 LOMENT 漢堡王 漢堡王 2000-10-11 00:00:00.000 1900-01-01 00:00:00.000 積極的 20 9
17 000015 施瓦茨 營地結構 營地結構 2005-07-24 00:00:00.000 1900-01-01 00:00:00.000 積極的 14 9
18 000016 游戲 內布拉斯加州拼箱 內布拉斯加州拼箱 2006-04-01 00:00:00.000 2020-07-13 00:00:00.000 不活躍 13 9

例如 output。 這些表總共包含幾千條記錄,包括截至今天的雇用日期和終止日期。

當我收集的數據較少時,一切都很好 例如下面的查詢:對於每個站點,2020 年初的活動數量,然后是到 2020 年的終止數量,然后是我到 2021 年的最終總活動數量。

SELECT
   F.[SITE]
  ,F.[ContractID]
  ,COUNT(CASE WHEN E.[DateOfHire] <= '2020-01-01 00:00:00.000'
      AND E.[Status] = 'Active' THEN 1 END) AS 'ACTIVE AT START OF 2020'

   ,COUNT(CASE WHEN E.[Status] = 'Inactive'
      AND E.[TermDate] > '2020-01-01 00:00:00.000'
      AND E.[TermDate] < '2021-01-01 00:00:00.000' THEN 1 END) AS 'Terminated Employees IN 2020'
   ,COUNT(CASE WHEN E.[DateOfHire] <= '2021-01-01 00:00:00.000'
       AND E.[Status] = 'Active' THEN 1 END) AS 'ACTIVE AT START OF 2021'

    FROM [websvr].[dbo].[Employees] AS E
      INNER JOIN [websvr].[dbo].[Facility] AS F
         ON E.HomeStationID = F.ID
    WHERE F.[ContractID] = 9
   GROUP BY F.[Site], F.[ContractID];

該查詢將像這樣 output :

地點 合同編號 2020 年初有效 於 2021 年終止 2021 年初生效
實驗室測試 16 9 5 7 10
麥當勞 9 48 11 52
麥克斯廷基 9 144 242 180
營地結構 9 17 0 18
內布拉斯加州拼箱 9 27 42 31
七十一堡 9 9 1 12
羅伯特堡K 9 4 5 4
騎吟游詩人 9 10 4 12
營地空閑用戶 9 5 1 7
漢堡王 9 39 25 49
填料 1 9 100 71 115
填料 2 9 287 99 301
填料 3 9 38 9 97
填料 4 9 9 6 33
填料 5 9 2 2 4
填料 6 9 10 2 14
填料 7 9 13 4 40

您可能已經注意到,這些示例都沒有包含周轉率列(定義如下)。 那是因為我最初打算在我拉出正確的列甚至計算周轉率之后使用 Power Bi 計算比率。 我搞砸了這個問題的標題,我應該指定我只需要獲取計算該字段所需的列。 無論如何,我現在被告知除了年度營業額外,我還需要能夠計算每個月底的營業額。 這甚至可以在單個查詢中實現嗎? 所以我上面的查詢讓我做年費率,排序......但是,我怎樣才能獲得每月周轉率所需的列以及每個站點的年份和? 此外,開始期間為 2020 年 1 月 1 日至當前日期。 只需將 go 追溯到 2020 年初。

為了計算營業額,我打算這樣做:*(一個月內的離職/當月月底我的在職員工總數)* 100

但是,我一直在努力獲得一個實際正確輸出數據的查詢。 因為,我的假設是我需要 select: 2020 年初的在職員工,月初的在職員工人數,一個月內的員工人數,一個月內的離職人數,月底的總人數,年末總活躍,全年終止 (我認為這是獲取我的數據所需的一切)

我不知道如何解決這個問題。

編輯:根據 Nick.McDermaid 的回復進一步審查后,我認為將年費率和月費率分開是理想的。 因此,兩個單獨的查詢是正確的舉措。 我可以輕松處理每年一次,但對於每月一次,我無法弄清楚如何計算月初和月底的活躍人數。 如何定義這兩個值的確切值?

再次編輯,我將在 SQL 側使用日歷表。 這個概念對我來說是新概念,如果有人有任何教育/學習資源可以幫助解釋將其連接到我現有的數據集以幫助我獲得所需的列所涉及的邏輯,我將不勝感激。 或有關解決此問題的任何其他建議。

這些列是:2020 年初的在職員工人數、月初的在職員工人數、一個月內的員工人數、一個月內的離職人數、月底的在職員工總數、月底的在職員工總數年,以及全年終止的總數

編輯:目前正在測試這個:非常感謝 Nick McDermaid。 我將把它更新為 go。

    DECLARE @Calendar table
    (
        [CalendarDate] DATETIME
    )
    
    DECLARE @StartDate DATETIME
    DECLARE @EndDate DATETIME
    SET @StartDate = '2020-01-01 00:00:00.000'
    SET @EndDate = GETDATE()
    
    WHILE @StartDate <= @EndDate
          BEGIN
                 INSERT INTO @Calendar
                 (
                       CalendarDate
                 )
                 SELECT
                       @StartDate
    
                 SET @StartDate = DATEADD(DD, 1, @StartDate)
          END
    
    SELECT CalendarDate AS 'Date'
    FROM @Calendar

編輯:目前根據 Nick McDermaid 的解決方案對此進行測試。 非常感謝他。

編輯:這是我的數據集。 大量員工試圖被檢索,這導致處理時間需要很長時間。 我在它結束之前終止了它。 另外,我忘記包含我的 where 子句來過濾contractid。

GO

DECLARE @Calendar table
 (
     [CalendarDate] DATE,
     CalendarMonth VARCHAR(7),
     IsSOM bit,
     IsEOM bit,
     IsSOY bit,
     IsEOY bit
 )

 DECLARE @StartDate DATETIME
 DECLARE @EndDate DATETIME
 SET @StartDate = '2000-01-01 00:00:00.000'
 SET @EndDate = GETDATE()

 WHILE @StartDate <= @EndDate
      BEGIN
             INSERT INTO @Calendar
             (
                    CalendarDate,
                    CalendarMonth,
                    IsSOM,
                    IsEOM,
                    IsSOY,
                    IsEOY
             )
             SELECT
                   @StartDate,
                   FORMAT(@StartDate,'yyyy-MM'),
                   CASE WHEN DATEPART(day,@StartDate)=1 THEN 1 ELSE 0 END As IsSOM,
                   CASE WHEN DATEPART(day,DATEADD(day,1,@StartDate))=1 THEN 1 ELSE 0 END As IsEOM,
                   CASE WHEN FORMAT(@StartDate,'ddMM')='0101' THEN 1 ELSE 0 END As IsSOY,
                   CASE WHEN FORMAT(@StartDate,'ddMM')='3112' THEN 1 ELSE 0 END As IsEOY

             SET @StartDate = DATEADD(DD, 1, @StartDate)
END


SELECT
C.CalendarMonth,
E.[Homestation],
-- When calculating Headcount at end of month,
-- only consider a record on the end of the month
SUM(CASE WHEN IsEOM=1 THEN 1 ELSE 0 END) AS EOMHeadcount,

-- Similar logic for start of month
SUM(CASE WHEN IsSOM=1 THEN 1 ELSE 0 END) AS SOMHeadcount,

-- To count Terminations, only count records
-- on days that there was a termination
SUM(CASE WHEN C.CalendarDate = E.TermDate THEN 1 ELSE 0 END) AS PeriodTerminations,

-- Similar logic for Hires
SUM(CASE WHEN C.CalendarDate = E.DateOfHire THEN 1 ELSE 0 END) AS PeriodHires
FROM
@Calendar C
LEFT JOIN
[websvr].[dbo].[Employees] AS E
ON C.CalendarDate BETWEEN E.DateOfHire AND IIF(E.TermDate = '1900-01-01','2100-01-01',E.TermDate)
 
GROUP BY C.CalendarMonth, E.[Homestation]
ORDER BY 1,2;

鑒於您迄今為止發布的內容,這是一般概念

設置樣本雇用和終止數據

請注意,如果您事先在問題中提供了此信息,那么回答問題會容易得多!

DECLARE @Sample table ([Location] VARCHAR(20), DateOfHire DATETIME, TermDate DATE, PayrollNo INT)

INSERT INTO @Sample ([Location] , DateOfHire , TermDate, PayrollNo)
VALUES 
('Camp Lucas','1999-12-27','2017-01-03',1),
('Burger King','2000-01-04','1900-01-01',2),
('The Swamp','2001-08-03','1900-01-01',3),
('The Swamp','2000-04-07','1900-01-01',4),
('The Swamp','2013-07-01','2017-07-01',5),
('Burger King','2016-02-01','2019-07-01',6),
('Camp Lucas','2000-06-12','2013-04-01',7),
('Camp Lucas','2008-08-01','2015-10-29',8)

設置日歷表

注意:您將經常使用它以使其成為真正的表格,日歷表格通常包含當地假期之類的內容,我在表格中添加了一些其他標志,這些標志使日期計算變得更加容易

 DECLARE @Calendar table
 (
     [CalendarDate] DATE,
     CalendarMonth VARCHAR(7),
     IsSOM bit,
     IsEOM bit,
     IsSOY bit,
     IsEOY bit
 )

 DECLARE @StartDate DATETIME
 DECLARE @EndDate DATETIME
 SET @StartDate = '2000-01-01 00:00:00.000'
 SET @EndDate = GETDATE()

 WHILE @StartDate <= @EndDate
      BEGIN
             INSERT INTO @Calendar
             (
                    CalendarDate,
                    CalendarMonth,
                    IsSOM,
                    IsEOM,
                    IsSOY,
                    IsEOY
             )
             SELECT
                   @StartDate,
                   FORMAT(@StartDate,'yyyy-MM'),
                   CASE WHEN DATEPART(day,@StartDate)=1 THEN 1 ELSE 0 END As IsSOM,
                   CASE WHEN DATEPART(day,DATEADD(day,1,@StartDate))=1 THEN 1 ELSE 0 END As IsEOM,
                   CASE WHEN FORMAT(@StartDate,'ddMM')='0101' THEN 1 ELSE 0 END As IsSOY,
                   CASE WHEN FORMAT(@StartDate,'ddMM')='3112' THEN 1 ELSE 0 END As IsEOY

             SET @StartDate = DATEADD(DD, 1, @StartDate)
      END

施展魔法

現在我們使用日歷作為驅動表——即使雇佣的人為零,我們也總是想要一個記錄,所以我們使用一個左連接到雇佣表。

我們使用between來匹配記錄。 因此,如果雇用表中的單個記錄描述了一個被雇用的人,然后在 40 天后被終止,這將導致該人有 40 條記錄,他們受雇的每一天都有一條記錄。

然后我們做一些“條件聚合”來檢查那些(例如)40條記錄中的各種東西。 然后我們總結並按月份和位置分組

SELECT 
C.CalendarMonth, 
S.Location, 
-- When calculating Headcount at end of month, 
-- only consider a record on the end of the month
SUM(CASE WHEN IsEOM=1 THEN 1 ELSE 0 END) AS EOMHeadcount,

-- Similar logic for start of month
SUM(CASE WHEN IsSOM=1 THEN 1 ELSE 0 END) AS SOMHeadcount,

-- To count Terminations, only count records 
-- on days that there was a termination
SUM(CASE WHEN C.CalendarDate = S.TermDate THEN 1 ELSE 0 END) AS PeriodTerminations,

-- Similar logic for Hires
SUM(CASE WHEN C.CalendarDate = S.DateOfHire THEN 1 ELSE 0 END) AS PeriodHires
FROM 
@Calendar C
LEFT JOIN 
@Sample S
ON C.CalendarDate BETWEEN S.DateOfHire AND IIF(S.TermDate = '1900-01-01','2100-01-01',S.TermDate)
GROUP BY C.CalendarMonth, S.Location
ORDER BY 1,2

試一試,如有任何問題,請與我聯系。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM