【问题标题】:Group records by consecutive dates when dates are not exactly consecutive当日期不完全连续时,按连续日期对记录进行分组
【发布时间】:2017-01-18 13:52:17
【问题描述】:

我有一些包含日期的数据。我正在尝试按连续日期对数据进行分组,但是日期并不完全连续。这是一个例子:

DateColumn              | Value
------------------------+-------
2017-01-18 01:12:34.107 | 215426 <- batch no. 1
2017-01-18 01:12:34.113 | 215636
2017-01-18 01:12:34.623 | 123516
2017-01-18 01:12:34.633 | 289926
2017-01-18 04:58:42.660 | 259063 <- batch no. 2
2017-01-18 04:58:42.663 | 261830
2017-01-18 04:58:42.893 | 219835
2017-01-18 04:58:42.907 | 250165
2017-01-18 05:18:14.660 | 134253 <- batch no. 3
2017-01-18 05:18:14.663 | 134257
2017-01-18 05:18:14.667 | 134372
2017-01-18 05:18:15.040 | 181679
2017-01-18 05:18:15.043 | 226368
2017-01-18 05:18:15.043 | 227070

数据是分批生成的,批处理中的每一行都需要几毫秒的时间来生成。我正在尝试将结果分组如下:

Date1                   | Date2                   | Count
------------------------+-------------------------+------
2017-01-18 01:12:34.107 | 2017-01-18 01:12:34.633 | 4
2017-01-18 04:58:42.660 | 2017-01-18 04:58:42.907 | 4
2017-01-18 05:18:14.660 | 2017-01-18 05:18:15.043 | 6

可以安全地假设,如果两个连续的行相隔超过 1 分钟,那么它们属于不同的批次。

我尝试了涉及ROW_NUMBER 函数的解决方案,但它们适用于连续日期(两行之间的日期差异是固定的)。当差异模糊时,如何达到预期的效果?


请注意,一个批处理可能比一分钟长得多。例如,一个批次可能包含从 2017-01-01 00:00:00 开始到 2017-01-01 00:05:00 结束的行,其中包含约 3000 行,每行相隔几十或几百毫秒。可以肯定的是,批次之间至少相隔 1 分钟。

【问题讨论】:

  • 我们不能说“它安全吗...” - 业务或其他领域专家将是唯一可以说的人。如果分批需要每个批次的标识符并使​​用它
  • 最后两行是否有相同的日期时间值或者是错字?
  • @vkp 这很奇怪,但不是错字。可能在 1 毫秒内插入了两行,或者实际时间四舍五入到最接近的 datetime 值。

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


【解决方案1】:

试试这个:

select min(t.dateColumn) date1, max(t.dateColumn) date2, count(*)
from (
    select t.*, sum(val) over (
            order by t.dateColumn
            ) grp
    from (
        select t.*, case 
                when datediff(ms, lag(t.dateColumn, 1, t.dateColumn) over (
                            order by t.dateColumn
                            ), t.dateColumn) > 60000
                    then 1
                else 0
                end val
        from your_table t
        ) t
    ) t
group by grp;

生产:

使用解析函数lag()根据datecolumn与上一个批次的差异标记下一个批次的开始,然后在其上使用解析sum()创建批次组,然后按其分组以查找所需聚合。

由于DATETIME 的舍入问题,组中可能存在一些错误分类。来自MSDN

日期时间值以 0.000、0.003 或 0.007 秒的增量四舍五入,如下表所示。


这是使用 CTE 重写的相同查询:

WITH cte1(DateColumn, ValueColumn) AS (
    -- Insert your query that returns a datetime column and any other column
    SELECT
        SomeDate,
        SomeValue
    FROM SomeTable
    WHERE SomeColumn IS NOT NULL
), cte2 AS (
    -- This query adds a column called "val" that contains
    -- 1 when current row date - previous row date > 1 minute
    -- 0 otherwise
    SELECT
        cte1.*,
        CASE WHEN DATEDIFF(MS, LAG(DateColumn, 1, DateColumn) OVER (ORDER BY DateColumn), DateColumn) > 60000 THEN 1 ELSE 0 END AS val
    FROM cte1
), cte3 AS (
    -- This query adds a column called "grp" that numbers 
    -- the groups using running sum over the "val" column
    SELECT
        cte2.*,
        SUM(val) OVER (ORDER BY DateColumn) AS grp
    FROM cte2
)
SELECT
    MIN(DateColumn) Date1,
    MAX(DateColumn) Date2,
    COUNT(ValueColumn) [Count]
FROM cte3
GROUP BY grp

【讨论】:

  • 创建群组的好方法
  • 不应该是datediff( second ...) &gt;60吗?
  • 考虑select datediff(mi,'2017-01-18 01:12:20', '2017-01-18 01:13:31'), datediff(second,'2017-01-18 01:12:20', '2017-01-18 01:13:31'),我的理解是应该是不同的组
  • 真的,datediff在左边,应该是1&gt;171 &gt; 60,不一样。
  • @GurV .. 我现在可以说这个逻辑是我的副本吗:)?
【解决方案2】:

DateColumn 中删除secondsmilliseconds 并进行分组

  select min(DateColumn), 
         max(DateColumn), 
         count(*)
  from Yourtable
  group by DATEADD(MINUTE, DATEDIFF(MINUTE, 0, DateColumn), 0)

这里有一些关于截断日期时间秒数的问题

Truncate seconds and milliseconds in SQL

A way to extract from a DateTime value data without seconds

【讨论】:

    【解决方案3】:

    如果您要比较日期之间的间隔(60 秒),这不起作用。但是你可以试试这个,如果你需要获取属于同一分钟 X 的记录。

    SELECT
         [Date1]    =   MIN([DateColumn])
        ,[Date2]    =   MAX([DateColumn])
        ,[Count]    =   COUNT([DateColumn]) 
    FROM
        [my_table]
    GROUP BY
        DATEADD(mi, DATEDIFF(mi, 0, [DateColumn]), 0);  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-23
      • 2021-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多