SQL按间隔分组,计数和求和

Posted

技术标签:

【中文标题】SQL按间隔分组,计数和求和【英文标题】:SQL Grouping by intervals, counting and summing 【发布时间】:2019-12-26 11:54:39 【问题描述】:

我需要找到在 Microsoft 服务器 SQL/T-SQL 中具有 15-20 年和超过 20 年工作经验的员工的总销售额。

我有一个看起来像这样的数据集:

    Hiredate       EmployeeID     Sales
0   1986-01-02     90             20,000
1   1989-02-30     80             10,000  
2   2000-01-20     91             50,000
3   2009-05-07     92             60,000
4   2007-07-06     47             30,000
5   1999-01-24     66             44,000
6   2005-09-22     21             30,000

到目前为止我所做的是:

   SELECT SUM(EmployeeID) 
   FROM (
   SELECT DATEDIFF(year,Hiredate, GETDATE()), COUNT(EmployeeID)
   FROM abc.table
   WHERE DATEDIFF(year, Hiredate, GETDATE()) > 20
   GROUP BY DATEDIFF(year,Hiredate, GETDATE())
   )

这部分给了我日期和员工人数的差异,但我不知道如何分开组然后总结销售额。

   SELECT DATEDIFF(year,Hiredate, GETDATE()), COUNT(EmployeeID)
   FROM abc.table
   WHERE DATEDIFF(year, Hiredate, GETDATE()) > 20
   GROUP BY DATEDIFF(year,Hiredate, GETDATE())

谢谢

【问题讨论】:

【参考方案1】:

您可以使用条件聚合:

select
    sum(case 
        when datediff(year, hiredate, getdate()) between 15 and 20 
        then sales 
        else 0 
    end) sales_15_20,
    sum(case 
        when datediff(year, hiredate, getdate()) > 20 
        then sales 
        else 0 
    end) sales_above_20
from mytable

此查询将为您提供包含两列的唯一记录,其中包含每个条件的销售额总和。

按照 Gordon Linoff 的以下建议,更优化的表述方式是:

select
    sum(case 
        when hiredate 
            between dateadd(year, -20, getdate()) and dateadd(year, -15, getdate())
        then sales 
        else 0 
    end) sales_15_20,
    sum(case 
        when hiredate < dateadd(year, -20, getdate()) 
        then sales 
        else 0 
    end) sales_above_20
from mytable

【讨论】:

【参考方案2】:

不要使用datediff()——它不会达到你的预期。它计算两个日期之间的“边界”数量。对于年份,即 12 月 31 日至 1 月 1 日之间的午夜。

此外,在列上应用函数通常会使创建最佳执行计划变得更加困难。

你似乎想要:

SELECT SUM(SALES) 
FROM abc
WHERE HireDate >= DATEADD(year, -20, GETDATE()) AND
      HireDate < DATEADD(year, -14 GETDATE());

要获取两个组的值,一种方法是条件聚合:

SELECT SUM(CASE WHEN HireDate >= DATEADD(year, -20, GETDATE()) AND
                     HireDate < DATEADD(year, -14 GETDATE())
                THEN SALES
           END),
        SUM(CASE WHEN HireDate < DATEADD(year, -20, GETDATE()) 
                 THEN SALES
           END)
FROM abc;

另一种是将值放在行中:

SELECT grp, SUM(sales)
FROM abc CROSS APPLY
     (VALUES (CASE WHEN HireDate < DATEADD(year, -20, GETDATE()) THEN '20+ YEARS'
                   WHEN HireDate < DATEADD(year, -14, GETDATE()) THEN '15-20 YEARS'
                   ELSE '< 15 YEARS'
              END)
     ) v(grp)
GROUP BY grp
ORDER BY MIN(HIREDATE);

【讨论】:

以上是关于SQL按间隔分组,计数和求和的主要内容,如果未能解决你的问题,请参考以下文章

按日期间隔大于 X 的 DATETIME 获取数据、计数和分组

按年龄分组和计数

每个时间间隔的事件分组和计数,加上运行总数

按 1 分钟间隔分组操作链 sql BigQuery

SQL查询中按日期、天间隔分组

如何在 Oracle SQL 上进行查询以获取时间间隔,按特定字段分组