我希望找到2015年上半年的平均员工人数。这是每个月的人数,1月 - 6月/ 6月(月)。这个数字是理想的结果。
例如,为简单起见,我们只需要3个月。 Jan有100,2月有105,Mar有103. 308/3 = 102.7平均员工。
不幸的是,我只剩下几列,我想生成一些干净的代码,以便完成我的任务。不知道如何使用我的信息完成此任务。
代码:
PersonId LastHireDate TerminationDate EmpStatus
19 2012-07-30 00:00:00.000 NULL RFT
20 2010-01-01 00:00:00.000 NULL RFT
21 2010-10-01 00:00:00.000 NULL RFT
24 1994-06-28 00:00:00.000 NULL RFT
25 2002-12-11 00:00:00.000 NULL RFT
26 2011-03-21 00:00:00.000 NULL RFT
27 2010-01-01 00:00:00.000 NULL RFT
30 2010-06-29 00:00:00.000 NULL PRN
34 2008-12-16 00:00:00.000 NULL RFT
35 2010-01-01 00:00:00.000 NULL RFT
36 2014-02-27 00:00:00.000 NULL RFT
37 2009-03-01 00:00:00.000 NULL PRN
39 2012-06-25 00:00:00.000 NULL RFT
40 2012-01-01 00:00:00.000 NULL RFT
42 2011-08-01 00:00:00.000 NULL RFT
44 2014-02-27 00:00:00.000 2014-09-27 00:00:00.000 RFT --hired before 2015-01-01 and leaves before 2015-01-01
54 2014-02-27 00:00:00.000 2015-05-15 00:00:00.000 RFT --hired before 2015-01-01 and leaves before 2015-06-30
676 2015-02-27 00:00:00.000 2015-06-15 00:00:00.000 RFT --hired after 2015-01-01 and leaves before 2015-06-30
3012 2015-03-20 00:00:00.000 2015-07-03 00:00:00.000 RFT --hired after 2015-01-01 and leaves after 2015-06-30
5125 2015-07-11 00:00:00.000 NULL RPT
5127 2015-07-07 00:00:00.000 NULL RFT
5129 2015-07-09 00:00:00.000 NULL PRN
5131 2015-07-07 00:00:00.000 NULL PRN
5133 2015-07-09 00:00:00.000 NULL PRN
5136 2015-07-13 00:00:00.000 NULL RFT
示例数据:
SELECT id
FROM your_table_name
WHERE CURDATE() >= `from`
AND CURDATE() <= `to`
答案 0 :(得分:2)
以下是SQL Fiddle,其中包含您更新的示例数据。那里有两个查询:第一个返回一个平均数,第二个返回每日数,以帮助理解它是如何工作的。按照日期,您可以看到人数来去时数字如何变化。
对于每个人,您需要知道两个日期:何时被雇用以及何时离开。我希望这是LastHireDate
和TerminationDate
的意思。我认为NULL
TerminationDate
意味着该人尚未离开,仍然受雇。
当我计算类似报告时,我会计算给定范围(而不是月份)中每天的就业人数。然后,您可以根据需要进一步平均每日数字。
我使用Calendar
表。这张表只列出了几十年的日期列表。
CREATE TABLE [dbo].[Calendar](
[dt] [date] NOT NULL,
CONSTRAINT [PK_Calendar] PRIMARY KEY CLUSTERED
(
[dt] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
在我的系统中,它只有很少的额外列,例如[IsLastDayOfMonth]
,[IsLastDayOfQuarter]
,这些列在某些报告中很有用,但在您的情况下,您只需要日期列。 populate such table的方法有很多种。
例如,从1900-01-01开始的100K行(~270年):
INSERT INTO dbo.Calendar (dt)
SELECT TOP (100000)
DATEADD(day, ROW_NUMBER() OVER (ORDER BY s1.[object_id])-1, '19000101') AS dt
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
OPTION (MAXDOP 1);
获得Calendar
表后,以下是使用方法:
WITH
CTE_EmployedPeople
-- this is how many people were employed on each day in the given period
AS
(
SELECT
dbo.Calendar.dt
,CAST(COUNT(*) as float) AS People -- without this cast the final average is int
FROM
dbo.Calendar
CROSS JOIN EmployeeTable
WHERE
(dbo.Calendar.dt >= '2015-01-01')
AND (dbo.Calendar.dt <= '2015-06-30')
AND (dbo.Calendar.dt >= EmployeeTable.LastHireDate)
AND (dbo.Calendar.dt <= EmployeeTable.TerminationDate
OR EmployeeTable.TerminationDate IS NULL)
GROUP BY dbo.Calendar.dt
)
,CTE_Daily
-- if it is possible that nobody was employed on a certain day
-- left join previous results to the Calendar table again to get 0 for such days
AS
(
SELECT
dbo.Calendar.dt
,ISNULL(CTE_EmployedPeople.People, 0) AS People
FROM
dbo.Calendar
LEFT JOIN CTE_EmployedPeople ON dbo.Calendar.dt = CTE_EmployedPeople.dt
WHERE
(dbo.Calendar.dt >= '2015-01-01')
AND (dbo.Calendar.dt <= '2015-06-30')
)
-- simple average of daily numbers
SELECT AVG(People) AS AvgPeople
FROM CTE_Daily;
答案 1 :(得分:2)
使用@ VladimirBaranov的答案获得通用解决方案。
但在您的特殊情况下,您可能不需要每月计算员工,然后对其进行平均。简单地将所要求的范围内使用的月数相加,然后将其除以6将返回相同的结果。
SELECT
-- approximate monthly average
SUM(datediff(month, start_dt, end_dt)+1) / 6.00,
-- exact daily average
SUM(datediff(day, start_dt, end_dt)+1)
/ cast(datediff(day, '2015-01-01', '2015-07-01') as float)
FROM
(
SELECT
LastHireDate
,TerminationDate
-- fixing start date to match the requested range
,CASE WHEN LastHireDate < '2015-01-01 00:00:00' THEN '2015-01-01 00:00:00' ELSE LastHireDate END AS start_dt
-- fixing end date to match the requested range
,CASE WHEN TerminationDate <= '2015-06-30 23:59:59' THEN TerminationDate ELSE '2015-06-30 23:59:59' END AS end_dt
FROM EmployeeTable AS a
WHERE a.OrgCodeIdNo = '69'
-- As @Turophile mentioned, your logic seems to be wrong,
-- your sample result shows employees hired after june 2015
AND (TerminationDate >= '2015-01-01 00:00:00'
OR (TerminationDate IS NULL AND a.employeestatus = 'Active')))
AND LastHireDate <= '2015-06-30 23:59:59'
) AS dt
如果员工在一个月内只雇用一天,这个解决方案会计算一个员工,当然这可能不是一个正确的平均值,这取决于您如何定义&#34;每月的员工数量&#34;。
编辑:
添加像VladimirBaranov这样的计算以获得每日平均值:
答案 2 :(得分:1)
你能使用DATEPART吗?
SELECT
COUNT( 1 ) / 6.0
FROM
EmployeeTable AS a
WHERE
OrgCodeIdNo = '69' AND
DATEPART( YEAR, TerminationDate ) = 2015 AND
DATEPART( MONTH, TerminationDate ) <= 6