查找YTD员工平均值

时间:2015-07-16 21:59:46

标签: sql sql-server sql-server-2012

我希望找到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`

3 个答案:

答案 0 :(得分:2)

以下是SQL Fiddle,其中包含您更新的示例数据。那里有两个查询:第一个返回一个平均数,第二个返回每日数,以帮助理解它是如何工作的。按照日期,您可以看到人数来去时数字如何变化。

对于每个人,您需要知道两个日期:何时被雇用以及何时离开。我希望这是LastHireDateTerminationDate的意思。我认为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这样的计算以获得每日平均值:

http://www.timeanddate.com/time/zones/cet

答案 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