SQL 查询:计数,按月-年分组,具有多个日期字段

Posted

技术标签:

【中文标题】SQL 查询:计数,按月-年分组,具有多个日期字段【英文标题】:SQL Query: Count, Group By Month-Year with Multiple Date Fields 【发布时间】:2020-01-30 19:26:33 【问题描述】:

我有一个如下所示的表格,其中所有列都是记录特定操作日期的日期字段。假设有 10 个这样的日期字段(仅使用我的查询/输出中的 10 个日期字段)

---------------------------------------------------------
| Date_Event1 | Date_Event2 | Date_Event3 | Date_Event4 |
---------------------------------------------------------
| NULL        | NULL        | 2019-03-04  | NULL        |
| 2019-01-07  | 2019-03-04  | 2019-02-08  | 2019-02-15  |
| 2019-01-04  | NULL        | 2019-02-10  | NULL        |
| NULL        | 2019-01-10  | NULL        | 2019-01-11  |
| 2019-02-04  | NULL        | 2019-03-04  | NULL        |
| NULL        | 2019-02-04  | 2019-03-20  | NULL        |
| 2019-01-04  | NULL        | 2019-02-13  | 2019-03-22  |

我正在尝试获取按月-年对所有列进行分组并计算每个月-年中每个 Date_Event 的出现次数的输出,类似于以下内容。

-----------------------------------------------------------------------
| Month-Year  | Date_Event1 | Date_Event2 | Date_Event3 | Date_Event4 |
-----------------------------------------------------------------------
| 01-2019     |      3      |      1      |     NULL    |      1      |
| 02-2019     |      1      |      1      |      3      |      1      |
| 03-2019     |     NULL    |      1      |      3      |      1      |

真的不知道从哪里开始

【问题讨论】:

你用的是sql server吗?你能标记一下sql平台吗 抱歉,使用的是postgresql平台 【参考方案1】:

这是一个对每一列进行子查询的示例。

SELECT RIGHT('0' + CAST(allDates.EventMonth AS CHAR(2)), 2) + '-' + CAST(allDates.EventYear AS CHAR(4)) AS [Month-Year],
    (SELECT COUNT(1) FROM EventTable WHERE DATEPART(YEAR, Date_Event1) = allDates.EventYear AND DATEPART(MONTH, Date_Event1) = allDates.EventMonth) AS Date_Event1,
    (SELECT COUNT(1) FROM EventTable WHERE DATEPART(YEAR, Date_Event2) = allDates.EventYear AND DATEPART(MONTH, Date_Event2) = allDates.EventMonth) AS Date_Event2,
    (SELECT COUNT(1) FROM EventTable WHERE DATEPART(YEAR, Date_Event3) = allDates.EventYear AND DATEPART(MONTH, Date_Event3) = allDates.EventMonth) AS Date_Event3,
    (SELECT COUNT(1) FROM EventTable WHERE DATEPART(YEAR, Date_Event4) = allDates.EventYear AND DATEPART(MONTH, Date_Event4) = allDates.EventMonth) AS Date_Event4
FROM (
    SELECT EventYear, EventMonth
    FROM (
        SELECT DATEPART(YEAR, Date_Event1) AS EventYear, DATEPART(MONTH, Date_Event1) AS EventMonth
        FROM EventTable
        UNION ALL
        SELECT DATEPART(YEAR, Date_Event2) AS EventYear, DATEPART(MONTH, Date_Event2) AS EventMonth
        FROM EventTable
        UNION ALL
        SELECT DATEPART(YEAR, Date_Event3) AS EventYear, DATEPART(MONTH, Date_Event3) AS EventMonth
        FROM EventTable
        UNION ALL
        SELECT DATEPART(YEAR, Date_Event4) AS EventYear, DATEPART(MONTH, Date_Event4) AS EventMonth
        FROM EventTable
        ) AS allDates
    GROUP BY EventYear, EventMonth
    ) AS allDates
ORDER BY allDates.EventYear, allDates.EventMonth

此示例使用 INNER JOIN,但根据表大小、索引可能会执行得更好。等等

SELECT RIGHT('0' + CAST(allDates.EventMonth AS CHAR(2)), 2) + '-' + CAST(allDates.EventYear AS CHAR(4)) AS [Month-Year],
    SUM(IIF(DATEPART(YEAR, e.Date_Event1) = allDates.EventYear AND DATEPART(MONTH, e.Date_Event1) = allDates.EventMonth, 1, 0)) AS Date_Event1,
    SUM(IIF(DATEPART(YEAR, e.Date_Event2) = allDates.EventYear AND DATEPART(MONTH, e.Date_Event2) = allDates.EventMonth, 1, 0)) AS Date_Event2,
    SUM(IIF(DATEPART(YEAR, e.Date_Event3) = allDates.EventYear AND DATEPART(MONTH, e.Date_Event3) = allDates.EventMonth, 1, 0)) AS Date_Event3,
    SUM(IIF(DATEPART(YEAR, e.Date_Event4) = allDates.EventYear AND DATEPART(MONTH, e.Date_Event4) = allDates.EventMonth, 1, 0)) AS Date_Event4,
FROM (
    SELECT EventYear, EventMonth
    FROM (
        SELECT DATEPART(YEAR, Date_Event1) AS EventYear, DATEPART(MONTH, Date_Event1) AS EventMonth
        FROM EventTable
        UNION ALL
        SELECT DATEPART(YEAR, Date_Event2) AS EventYear, DATEPART(MONTH, Date_Event2) AS EventMonth
        FROM EventTable
        UNION ALL
        SELECT DATEPART(YEAR, Date_Event3) AS EventYear, DATEPART(MONTH, Date_Event3) AS EventMonth
        FROM EventTable
        UNION ALL
        SELECT DATEPART(YEAR, Date_Event4) AS EventYear, DATEPART(MONTH, Date_Event4) AS EventMonth
        FROM EventTable
        ) AS allDates
    GROUP BY EventYear, EventMonth
    ) AS allDates
INNER JOIN EventTable AS e ON 1 = 1
GROUP BY allDates.EventYear, allDates.EventMonth
ORDER BY allDates.EventYear, allDates.EventMonth

【讨论】:

谢谢,效果很好!对于其他可能正在看这个的人,我最终使用了带有 INNER JOIN 的那个,因为它处理了一半的时间,并用 CASE/WHEN 切换了 IIF 函数以在 Redshift 中使用。感谢您的帮助!【参考方案2】:

您可以将其扩展到更多列

对于 SQL Server

with cte as 
(
select  NULL   as Date_Event1    , NULL  as Date_Event2    , '2019-03-04' as Date_Event3, NULL  as Date_Event4
union select '2019-01-07', '2019-03-04', '2019-02-08', '2019-02-15'
union select '2019-01-04', NULL      , '2019-02-10', NULL      
union select NULL       , '2019-01-10', NULL      , '2019-01-11'
union select '2019-02-04', NULL      , '2019-03-04', NULL      
union select NULL       , '2019-02-04', '2019-03-20', NULL      
union select '2019-01-04', NULL      , '2019-02-13', '2019-03-22'
),
yyyydd as
(
        select CONVERT(VARCHAR(7), Date_Event1, 126) as [Month-Year] from cte where Date_Event1 is not null
union   select CONVERT(VARCHAR(7), Date_Event2, 126) from cte where Date_Event2 is not null
union   select CONVERT(VARCHAR(7), Date_Event3, 126) from cte where Date_Event3 is not null
union   select CONVERT(VARCHAR(7), Date_Event4, 126) from cte where Date_Event4 is not null
)

    select [Month-Year] 
    , ( select sum(case when b.Date_Event1 is null then null else 1 end) from cte b where a.[Month-Year] = CONVERT(VARCHAR(7), b.Date_Event1, 126)  ) as Date_Event1 
    , ( select sum(case when b.Date_Event2 is null then null else 1 end) from cte b where a.[Month-Year] = CONVERT(VARCHAR(7), b.Date_Event2, 126)  ) as Date_Event1 
    , ( select sum(case when b.Date_Event3 is null then null else 1 end) from cte b where a.[Month-Year] = CONVERT(VARCHAR(7), b.Date_Event3, 126)  ) as Date_Event1 
    , ( select sum(case when b.Date_Event4 is null then null else 1 end) from cte b where a.[Month-Year] = CONVERT(VARCHAR(7), b.Date_Event4, 126)  ) as Date_Event1 
    from yyyydd a 

【讨论】:

以上是关于SQL 查询:计数,按月-年分组,具有多个日期字段的主要内容,如果未能解决你的问题,请参考以下文章

sql中如何把具体日期转化为按月排序?

如何使用sql从日期字段按月分组

LINQ:在日期时间字段中按月和年分组

按月分组的运行计数以汇总销售额

SQL按月统计,按日分组

如何简化 Laravel 查询以按年搜索日期并按月分组