【问题标题】:How can I return the total count of distinct column values for each month in current year, the months should return as column headers如何返回当年每个月的不同列值的总数,月份应作为列标题返回
【发布时间】:2019-11-24 00:17:31
【问题描述】:

我正在尝试查询一个表以返回本年度每个月的项目中不同用户的总数。我的查询有效,除了它返回 2 行,其中每个月有每个项目的用户总数(其中计算了重复的用户,我不想要)。第二行正是我想要的。

如何修复我的查询以仅返回第二行数据?

下面我有一个示例表和我想出的查询:

CREATE TABLE [table_emp]
    ([Username] varchar(8), [Project] varchar(8), [Hours] int, [DateInfo] date);

INSERT INTO [table_emp]
    ([Username], [Project], [DateInfo])
VALUES
    ('userA', 'ProjectA', 5, '2019-03-19 00:00:00'),
    ('userA', 'ProjectA', 5, '2019-03-07 00:00:00'),
    ('userB', 'ProjectA', 5, '2019-03-07 00:00:00'),
    ('userB', 'ProjectB', 2, '2019-11-12 00:00:00'),
    ('userB', 'ProjectC', 1, '2019-11-12 00:00:00');
SELECT 
  SUM(CASE datepart(month,DateInfo) WHEN 1 THEN 1 ELSE 0 END) AS 'January',
  SUM(CASE datepart(month,DateInfo) WHEN 2 THEN 1 ELSE 0 END) AS 

'February',
  SUM(CASE datepart(month,DateInfo) WHEN 3 THEN 1 ELSE 0 END) AS 'March',
  SUM(CASE datepart(month,DateInfo) WHEN 4 THEN 1 ELSE 0 END) AS 'April',
  SUM(CASE datepart(month,DateInfo) WHEN 5 THEN 1 ELSE 0 END) AS 'May',
  SUM(CASE datepart(month,DateInfo) WHEN 6 THEN 1 ELSE 0 END) AS 'June',
  SUM(CASE datepart(month,DateInfo) WHEN 7 THEN 1 ELSE 0 END) AS 'July',
  SUM(CASE datepart(month,DateInfo) WHEN 8 THEN 1 ELSE 0 END) AS 'August',
  SUM(CASE datepart(month,DateInfo) WHEN 9 THEN 1 ELSE 0 END) AS 

'September',
  SUM(CASE datepart(month,DateInfo) WHEN 10 THEN 1 ELSE 0 END) AS 

'October',
  SUM(CASE datepart(month,DateInfo) WHEN 11 THEN 1 ELSE 0 END) AS 

'November',
  SUM(CASE datepart(month,DateInfo) WHEN 12 THEN 1 ELSE 0 END) AS 

'December',
  SUM(CASE datepart(year,DateInfo) WHEN YEAR(GETDATE()) THEN 1 ELSE 0 END) 

AS 'TOTAL'

FROM
    table_emp
WHERE
   YEAR(DateInfo) = YEAR(GETDATE())

   GROUP BY Username;


+---------+----------+-------+-------+-----+------+------+--------+-----------+---------+----------+----------+-------+
| January | February | March | April | May | June | July | August | September | October | November | December | Total |
+---------+----------+-------+-------+-----+------+------+--------+-----------+---------+----------+----------+-------+
|       0 |        0 |     2 |     0 |   0 |    0 |    0 |      0 |         0 |       0 |        0 |        0 |     2 |
|       0 |        0 |     1 |     0 |   0 |    0 |    0 |      0 |         0 |       0 |        2 |        0 |     3 |
+---------+----------+-------+-------+-----+------+------+--------+-----------+---------+----------+----------+-------+





我期待下面的回报:


+---------+----------+-------+-------+-----+------+------+--------+-----------+---------+----------+----------+-------+
| January | February | March | April | May | June | July | August | September | October | November | December | Total |
+---------+----------+-------+-------+-----+------+------+--------+-----------+---------+----------+----------+-------+
|       0 |        0 |     1 |     0 |   0 |    0 |    0 |      0 |         0 |       0 |        2 |        0 |     3 |
+---------+----------+-------+-------+-----+------+------+--------+-----------+---------+----------+----------+-------+

【问题讨论】:

  • 考虑使用 PIVOT 而不是所有这些 CASE 语句。一开始可能会更困难,但会产生更简洁的代码。签出this

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


【解决方案1】:

您的基于条件聚合的逻辑没问题,但是您应该考虑以下修复:

  • 删除GROUP BY Username子句;这将为每个用户提供一条记录,这显然不是您想要的
  • 不要SUM();而是每月COUNT(DISTINCT ) 个用户名
  • 我还建议进行明确的日期比较,而不是使用日期函数;这允许 SQL Server 利用DateInfo 上的索引;这有效,因为您正在过滤当前年份。

查询:

SELECT 
    COUNT(DISTINCT CASE
        WHEN DateInfo >= '2019-01-01' AND DateInfo < '2019-02-01' 
        THEN Username 
    END) AS [January],
    COUNT(DISTINCT CASE
        WHEN DateInfo >= '2019-01-02' AND DateInfo < '2019-02-03' 
        THEN Username 
    END) AS [February],
    -- repeat for other months
    COUNT(DISTINCT Username) AS [TOTAL}
FROM table_emp
WHERE DateInfo >= '2019-01-01' AND DateInfo < '2020-01-01'

旁注:不要使用单引号作为标识符;单引号应仅用于字符串字面量(这是 SQL 标准)。相反,请使用方括号 ([]),这就是 SQL Server 的做法。

【讨论】:

  • 这似乎是正确的。我确实注意到,即使用户在某个月份没有任何数据,Total 也会计算每个用户。所以我将总数修改为: COUNT(DISTINCT CASE WHEN DateInfo >= '2019-01-01' AND DateInfo
  • @Dr.Prog:我认为你不需要这个,因为WHERE 子句已经过滤了年份范围。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-26
  • 1970-01-01
  • 2017-12-05
相关资源
最近更新 更多