SQL Server 按月、日和小时划分多个分区

Posted

技术标签:

【中文标题】SQL Server 按月、日和小时划分多个分区【英文标题】:SQL Server multiple partitions by month, day and hour 【发布时间】:2020-06-15 17:03:17 【问题描述】:

在 SQL Server 中,我有一个如下表:

processName   initDateTime           
processA      2020-06-15 13:31:15.330
processB      2020-06-20 10:00:30.000
processA      2020-06-20 13:31:15.330
...
and so on

我需要按 processName 分组,对于每个 processName,我需要按月 (#byMonth)、日 (#byDay) 和小时 (#byHour) 获取记录数。

最好的方法是什么?下面的东西? SQL 查询是什么?

可能的结果:

processName Month    Day  Hour  #byMonth #byDay #byHour #total(by process)
processA    January  15   17    4         3     2       7
processA    January  15   20    4         3     1       7
processA    January  20   05    4         2     3       7
processA    January  20   13    4         2     1       7
processA    March    04   05    3         2     3       7
processA    March    04   17    3         2     2       7
processA    March    15   05    3         3     3       7

...and so on for the rest of processes name

【问题讨论】:

【参考方案1】:

我认为你想要聚合和窗口函数:

select 
    processName,
    month(initDateTime),
    day(initDateTime),
    datepart(hour, initDateTime),
    sum(count(*)) over(partition by processName, year(initDateTime), month(initDateTime)) byMonth,
    sum(count(*)) over(partition by processName, year(initDateTime), month(initDateTime), day(initDateTime)) byDay,
    count(*) byHour
from mytable
group by 
    processName,
    year(initDateTime),
    month(initDateTime),
    day(initDateTime),
    datepart(hour, initDateTime)

【讨论】:

正是我想要的。只有一件事,你忘了在 byDay 之前加上括号。【参考方案2】:

只要有可能,我喜欢将日期作为日期返回给调用者,以便他们也可以将它们作为日期处理,例如排序、转换为本地时间,甚至确保显示的语言是相关的。所以如果是我,我会这样做:

-- sample data
CREATE TABLE #T (processName VARCHAR(50), initDateTime  DATETIME)
INSERT #T (processName, initDateTime)
VALUES
    ('processA', '2020-06-15 13:31:15.330'),
    ('processB', '2020-06-20 10:00:30.000'),
    ('processA', '2020-06-20 13:31:15.330')


SELECT  t.processName,
        i.InitHour,
        ByMonth = SUM(COUNT(*)) OVER(PARTITION BY i.InitMonth),
        ByDay = SUM(COUNT(*)) OVER(PARTITION BY i.InitDay),
        ByHour = COUNT(*)
FROM    #T AS t
        CROSS APPLY
        (   SELECT  InitHour = DATEADD(HOUR, DATEDIFF(HOUR, 0, initDateTime), 0), 
                    InitDay = DATEADD(DAY, DATEDIFF(DAY, 0, initDateTime), 0),
                    InitMonth = DATEADD(MONTH, DATEDIFF(MONTH, 0, initDateTime), 0)
        ) AS i
GROUP BY t.processName, i.InitHour, i.InitDay, i.InitMonth;

返回:

processName     InitHour                ByMonth ByDay   ByHour
--------------------------------------------------------------
processA        2020-06-15 13:00:00     3       1       1
processA        2020-06-20 13:00:00     3       2       1
processB        2020-06-20 10:00:00     3       2       1

如果你需要SQL中的日期、月份名称等,你可以使用DATEPARTDATENAME来获取这些,但是如上所述,这在表示层中处理得更好,所以你可以处理语言环境,或特定的用户设置。

【讨论】:

以上是关于SQL Server 按月、日和小时划分多个分区的主要内容,如果未能解决你的问题,请参考以下文章

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

SQL Server 2008 R2-查询以获取按月销售的总销售额和数量

按日期降序排列 - 月、日和年

Sql Server系列:分区表操作

SQL Server 数据分区管理

SQL Server 数据分区管理