【问题标题】:SQL - Grouping with aggregationSQL - 聚合分组
【发布时间】:2012-09-09 23:43:09
【问题描述】:

我有一个表 (TABLE1),其中列出了所有员工及其部门 ID、他们开始的日期和终止的日期(NULL 表示他们是当前员工)。

我想要一个结果集 (TABLE2) ,其中每一行代表从第一个员工入职以来的一天(在下面的示例表中,该日期是 20090101 ),直到今天。 (日期字段)。我想按 DeptID 对员工进行分组,并计算 TABLE2 每一行的员工总数。

我该如何查询?提前感谢您的帮助。

表 1

DeptID     EmployeeID   StartDate   EndDate
--------------------------------------------
001        123           20100101   20120101   
001        124           20090101   NULL
001        234           20110101   20120101

表2

DeptID       Date      EmployeeCount
-----------------------------------
001          20090101     1
001          20090102     1
...          ...          1
001          20100101     2
001          20100102     2
...          ...          2
001          20110101     3
001          20110102     3
...          ...          3
001          20120101     1
001          20120102     1
001          20120103     1
...          ...          1

【问题讨论】:

  • 一种方法是使用numbers table 扩展表 1 中的所有日期范围,然后按 DeptID 和 Date 分组以计算行数。
  • 你的日期列表来自哪里?

标签: sql sql-server-2008 tsql group-by


【解决方案1】:

如果您有 date 查找表,这将起作用。您将需要指定部门 ID。在action 中查看。

查询

SELECT d.dt, SUM(e.ecount) AS RunningTotal 
FROM dates d
INNER JOIN
  (SELECT b.dt, 
    CASE
      WHEN c.ecount IS NULL THEN 0
      ELSE c.ecount
    END AS ecount
  FROM dates b 
  LEFT JOIN
    (SELECT a.DeptID, a.dt, SUM([count]) AS ecount
    FROM
       (SELECT DeptID, EmployeeID, 1 AS [count], StartDate AS dt FROM TABLE1
        UNION ALL
        SELECT DeptID, EmployeeID, 
          CASE
            WHEN EndDate IS NOT NULL THEN -1
            ELSE 0
          END AS [count], EndDate AS dt FROM TABLE1) a
    WHERE a.dt IS NOT NULL AND DeptID = 1
    GROUP BY a.DeptID, a.dt) c ON c.dt = b.dt) e ON e.dt <= d.dt
GROUP BY d.dt

结果

| DT |运行总计 | ----------------------------------------- | 2009-01-01 | 1 | | 2009-02-01 | 1 | | 2009-03-01 | 1 | | 2009-04-01 | 1 | | 2009-05-01 | 1 | | 2009-06-01 | 1 | | 2009-07-01 | 1 | | 2009-08-01 | 1 | | 2009-09-01 | 1 | | 2009-10-01 | 1 | | 2009-11-01 | 1 | | 2009-12-01 | 1 | | 2010-01-01 | 2 | | 2010-02-01 | 2 | | 2010-03-01 | 2 | | 2010-04-01 | 2 | | 2010-05-01 | 2 | | 2010-06-01 | 2 | | 2010-07-01 | 2 | | 2010-08-01 | 2 | | 2010-09-01 | 2 | | 2010-10-01 | 2 | | 2010-11-01 | 2 | | 2010-12-01 | 2 | | 2011-01-01 | 3 | | 2011-02-01 | 3 | | 2011-03-01 | 3 | | 2011-04-01 | 3 | | 2011-05-01 | 3 | | 2011-06-01 | 3 | | 2011-07-01 | 3 | | 2011-08-01 | 3 | | 2011-09-01 | 3 | | 2011-10-01 | 3 | | 2011-11-01 | 3 | | 2011-12-01 | 3 | | 2012-01-01 | 1 |

架构

CREATE TABLE TABLE1 (
  DeptID tinyint,
  EmployeeID tinyint,
  StartDate date,
  EndDate date)

INSERT INTO TABLE1 VALUES 
(1, 123, '2010-01-01', '2012-01-01'),
(1, 124, '2009-01-01', NULL),
(1, 234, '2011-01-01', '2012-01-01')

CREATE TABLE dates (
  dt date)

INSERT INTO dates VALUES 
('2009-01-01'), ('2009-02-01'), ('2009-03-01'), ('2009-04-01'), ('2009-05-01'), 
('2009-06-01'), ('2009-07-01'), ('2009-08-01'), ('2009-09-01'), ('2009-10-01'), 
('2009-11-01'), ('2009-12-01'), ('2010-01-01'), ('2010-02-01'), ('2010-03-01'), 
('2010-04-01'), ('2010-05-01'), ('2010-06-01'), ('2010-07-01'), ('2010-08-01'), 
('2010-09-01'), ('2010-10-01'), ('2010-11-01'), ('2010-12-01'), ('2011-01-01'), 
('2011-02-01'), ('2011-03-01'), ('2011-04-01'), ('2011-05-01'), ('2011-06-01'), 
('2011-07-01'), ('2011-08-01'), ('2011-09-01'), ('2011-10-01'), ('2011-11-01'), 
('2011-12-01'), ('2012-01-01')

【讨论】:

    【解决方案2】:

    你需要一些类似的东西。

    SELECT  *
          , ( SELECT    COUNT(EmployeeID) AS EmployeeCount 
              FROM      TABLE1 AS f
              WHERE     t.[Date] BETWEEN f.BeginDate AND f.EndDate
            )
    FROM    ( SELECT    DeptID
                      , BeginDate AS [Date]
              FROM      TABLE1
              UNION
              SELECT    DeptID
                      , EndDate AS [Date]
              FROM      TABLE1
            ) AS t
    

    编辑,因为 OP 澄清说他希望这里的所有日期都是更新后的解决方案 如果员工的工作在该日期结束,我已将其排除在计数之外。但是,如果您想在以下解决方案中包括将 t.[Date] &lt; f.EndDate 更改为 t.[Date] &lt;= f.EndDate。另外,我假设 EndDate 中的NULL 值意味着员工仍然为部门工作。

    DECLARE @StartDate DATE = (SELECT MIN(StartDate) FROM Table1)
           ,@EndDate DATE = (SELECT MAX(EndDate) FROM Table1)
    
    ;WITH CTE AS 
    (
    SELECT DISTINCT DeptID,@StartDate AS [Date] FROM Table1
    UNION ALL
    SELECT c.DeptID, DATEADD(dd,1,c.[Date]) AS [Date] FROM CTE AS c
    WHERE c.[Date]<=@EndDate
    )
    SELECT  * ,
            EmployeeCount=( SELECT    COUNT(EmployeeID) 
              FROM      TABLE1 AS f
              WHERE     f.DeptID=t.DeptID AND  t.[Date] >= f.StartDate
                        AND ( t.[Date] < f.EndDate OR f.EndDate IS NULL )
            )
    FROM    CTE AS t
    ORDER BY 1
    OPTION  ( MAXRECURSION 0 )
    

    这里是 SQL Fiddler 演示。我添加了另一个部门并添加了一个员工。

    http://sqlfiddle.com/#!3/5c4ec/1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-20
      • 2018-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-08
      相关资源
      最近更新 更多