SQL - 在日期桶中放置值

Posted

技术标签:

【中文标题】SQL - 在日期桶中放置值【英文标题】:SQL - placing values in date bucket 【发布时间】:2021-12-14 10:51:31 【问题描述】:

作为一个 SQL 新手确实在为此苦苦挣扎,所以我需要根据一天中的时间将 is_registered 列中的值放入每小时存储桶中。下面是一个小样本

creation date is_registered
2021-10-28 00:03:12.240 1
2021-10-28 00:09:16.221 1
2021-10-28 00:12:23.234 1
2021-10-29 00:03:19.240 1
2021-10-29 00:48:12:190 1
2021-10-29 01:09:36:129 1
2021-10-29 01:29:29:120 1

我想要达到的结果(使用完整的数据集)如下(一天中每个小时的存储桶

Date Hour Bucket Total in each bucket
2021-10-28 00:00-01:00 289
2021-10-28 01:00-02:00 876
-------- -------------- -------------
2021-10-29 00:00-01:00 190
2021-10-29 01:00-02:00 309

等等。

希望提供足够的信息,任何帮助将不胜感激,谢谢

【问题讨论】:

因此,如果一行在 1:00 被“注册”,它是否计入前 2 个输出行?将 1 小时视为从 0:0:0 到 1:0:0(61 分钟)是一个常见的错误。 对不起,应该更清楚,如果在 12:59 注册,它将下降到 12:00 所以 00:00-01:00 reg at 01:00:19 将是 01:00- 02:00 Refer to this 【参考方案1】:

试试下面的方法

    --Create table script

CREATE TABLE [dbo].[Table_4](
    [creationdate] [datetime] NULL,
    [isreg] [int] NULL
) ON [PRIMARY]
GO

    --Sample data
    
    insert into table_4 values (getdate(),1)
    insert into table_4 values (getdate()-1,1)
    go
    
    
    -- query
    WITH report(N) AS(
        SELECT TOP(23) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM sys.columns
    )
    ,hourly(creationdate) AS(
        SELECT DATEADD(HOUR, t.N, d.creationdate)
        FROM report t
        CROSS JOIN(
            SELECT DISTINCT DATEADD(DD, DATEDIFF(DD, 0, creationdate), 0) AS creationdate FROM table_4
        ) d
    )
    SELECT
       convert(date, h.creationdate) as [Creation date],
       convert(varchar(5), DATEPART(HOUR, h.creationdate)-1)+ ' - ' + convert(varchar(5),DATEPART(HOUR, h.creationdate)) as [Hour Bucket], 
        [Total in each bucket] = ISNULL(t.isreg, 0)
    FROM hourly h
    LEFT JOIN(
        SELECT
            creationdate = DATEADD(HOUR, DATEPART(HOUR, creationdate) ,DATEADD(DD, DATEDIFF(DD, 0, creationdate), 0)),
            isreg = COUNT(*)
        FROM table_4
        GROUP BY DATEADD(DD, DATEDIFF(DD, 0, creationdate), 0), DATEPART(HOUR, creationdate)
    )t
        ON t.creationdate = h.creationdate
        order by h.creationdate

Reference link

【讨论】:

谢谢 Malvik,为什么需要创建表和插入示例数据? 我已经用我的示例数据添加了答案。如果您具有相同的结构,则不需要创建该表并插入示例数据。【参考方案2】:

使用这个 tvf 可能更易于维护: DateRange TVF

 WITH Ranges
 AS
 (
    SELECT [Value] AS date_from
        ,LEAD([Value]) OVER (ORDER BY [Value]) AS date_to
        ,CAST([Value] AS date) AS [Date]
        ,CONVERT(char(5), [Value], 14) + '-'
            + CONVERT(char(5), LEAD([Value]) OVER (ORDER BY [Value]), 14) AS Hour_Bucket
    FROM dbo.DateRange('2021-10-28', '2021-10-30', 'hh', 1)
)
SELECT R.[Date], R.Hour_Bucket
    ,COUNT(T.is_registered) AS Total_Registered
FROM Ranges R
    LEFT JOIN YourTable T
        ON T.creation_date >= R.date_from
            AND T.creation_date < R.date_to
            AND T.is_registered = 1
WHERE R.date_to IS NOT NULL
GROUP BY R.[Date], R.Hour_Bucket
ORDER BY [Date], Hour_Bucket;

【讨论】:

以上是关于SQL - 在日期桶中放置值的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL 中为日期分配序号

希望在画面中创建动态日期桶

具有两个或多个日期范围的 MDX 查询

通过 CLI 将存储桶中的 AVRO 加载到具有日期分区的 BigQuery 中

将 current_date 转换为相对日期和静态时间

Symfony/Doctrine 中的 SQL 注入