[英]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.