我有如下员工:
DECLARE @Employees TABLE
(
[EmployeeID] [int] IDENTITY(1,1) NOT NULL,
[HireDate] [datetime] NOT NULL,
[TerminationDate] [datetime] NULL
)
INSERT INTO @Employees (HireDate, TerminationDate) VALUES ('2016/01/01','2016/01/02')
INSERT INTO @Employees (HireDate, TerminationDate) VALUES ('2016/02/01', '2017/01/30')
INSERT INTO @Employees (HireDate, TerminationDate) VALUES ('2016/03/01', '2016/05/05')
如果我需要知道 2016 年 2 月在职员工的数量,我使用了以下查询:
SELECT * FROM @Employees
WHERE HireDate <= '2016-02-28' AND TerminationDate >= '2016-02-28'
但是,我很难找到一种简单的方法来找到每个月的活跃员工。例如,我想了解2016年1月到2017年1月每个月在职员工的数量。
我是否需要每个月都有单独的表格并使用一些 CTE 来交叉引用两个表格并提供每个月的报告?任何指示将不胜感激。
根据到目前为止的输入,我已经做到了这一点。它似乎工作正常,除了 2016 年 1 月,我有一名员工活跃,尽管只有 2 天,但它没有报告,因为我知道我正在月底验证。有什么调整吗?
DECLARE @startDate DATETIME
DECLARE @endDate datetime
SET @startDate='2014-01-31'
SET @endDate='2017-05-31'
DECLARE @Employees TABLE
(
[EmployeeID] [int] IDENTITY(1,1) NOT NULL,
[HireDate] [datetime] NOT NULL,
[TerminationDate] [datetime] NULL
)
INSERT INTO @Employees (HireDate, TerminationDate) VALUES ('2016/01/01','2016/01/02')
INSERT INTO @Employees (HireDate, TerminationDate) VALUES ('2016/02/01', '2017/01/30')
INSERT INTO @Employees (HireDate, TerminationDate) VALUES ('2016/03/01', '2016/05/05')
;With MyListOfDates( MyCalendarMonthEnd )
AS
(
SELECT @startDate MyCalendarMonthEnd
UNION ALL
SELECT DATEADD(MONTH, 1, MyCalendarMonthEnd)
FROM MyListOfDates
WHERE MyCalendarMonthEnd < @endDate
)
SELECT YEAR(mld.MyCalendarMonthEnd) Year, MONTH(mld.MyCalendarMonthEnd) Month, COUNT(*) ActiveEmployeeCount
FROM MyListOfDates mld
JOIN @Employees e on 1 = 1
WHERE e.HireDate <= mld.MyCalendarMonthEnd and e.TerminationDate >= mld.MyCalendarMonthEnd
GROUP BY mld.MyCalendarMonthEnd
最佳答案
一种选择是使用临时统计表。计数/日历表也可以达到目的
我选择了 DatePart DAY 来捕获该月的任何部分
示例
Declare @Date1 date = '2016-01-01'
Declare @Date2 date = '2017-01-31'
Select Year = DatePart(YEAR,D)
,Month = DatePart(MONTH,D)
,EmpCnt = count(DISTINCT [EmployeeID])
From (Select Top (DateDiff(DAY,@Date1,@Date2)+1) D=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),@Date1) From master..spt_values n1,master..spt_values n2) A
Left Join @Employees B on D between [HireDate] and IsNull([TerminationDate],GetDate())
Group By DatePart(YEAR,D), DatePart(MONTH,D)
Order By 1,2
返回
Year Month EmpCnt
2016 1 1
2016 2 1
2016 3 2
2016 4 2
2016 5 2
2016 6 1
2016 7 1
2016 8 1
2016 9 1
2016 10 1
2016 11 1
2016 12 1
2017 1 1
As Requested - Some Commentary
首先,我们创建 X 和 Y 之间的一系列日期。这是通过临时统计表、Row_Number() 和 DateAdd() 完成的。例如:
Declare @Date1 date = '2016-01-01'
Declare @Date2 date = '2017-01-31'
Select Top (DateDiff(DAY,@Date1,@Date2)+1) D=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),@Date1)
From master..spt_values n1,master..spt_values n2
返回
D
2016-01-01
2016-01-02
2016-01-03
2016-01-04
...
2017-01-29
2017-01-30
2017-01-31
请注意,我们正在对 spt_values(n1 和 n2)执行交叉连接。这是因为 spt_values 只有 2,523 条记录(或天)。考虑到这仅相当于 6 年,通过使用交叉连接将潜在的时间跨度扩展为 630 万天——这是一个荒谬的数字,但您永远不会看到这个数量,因为我们指定 TOP ( nDays )
一旦我们有了目标天数的数据集,我们就会对 EMPLOYEE 表执行 LEFT JOIN,其中 D 位于雇用日期和任期日期之间。这实际上创建了一个大型时间数据集。例如,如果一名员工仅活跃 10 天,我们将看到 10 条记录。每天 1 次。
然后我们执行一个简单的聚合COUNT(DISTINCT EmployeeID)
按年和月分组。
关于sql - 获取每月活跃员工数量的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43875894/