sql-server - 如何按日期容限对记录进行分组?

标签 sql-server t-sql

DROP TABLE IF EXISTS  #Groups;

CREATE TABLE #Groups 
(
     [entity] nvarchar(30), 
     [workItem] nvarchar(255), 
     [CreatedDate] datetime
)

INSERT INTO #Groups ([entity], [workItem], [CreatedDate])
VALUES
( N'5002', N'AG', N'2020-09-04T13:24:00.823' ), 
( N'5002', N'AG', N'2020-09-04T13:23:05.103' ), 
( N'5002', N'AG', N'2020-09-04T14:23:05.103' ), 
( N'5002', N'SH', N'2020-09-04T13:26:42.367' ), 
( N'5002', N'SH', N'2020-09-04T13:27:17.25'  ), 
( N'5003', N'SH', N'2020-10-04T15:36:42.367' ), 
( N'5003', N'SH', N'2020-10-04T15:37:17.25'  );

预期结果:

entity  workItem    CreatedDate
--------------------------------------------
5002    AG          2020-09-04 13:24:00.823
5002    AG          2020-09-04 14:23:05.103
5002    SH          2020-09-04 13:27:17.250
5003    SH          2020-10-04 15:37:17.250

基本上,我需要按实体、工作项和日期进行分组,容差为一分钟。

这是我的尝试(尽管我没有走得太远):

SELECT
    t1.entity,
    t1.workItem,
    t1.CreatedDate,
    LAG(t1.CreatedDate, 1) OVER (PARTITION BY   t1.entity, t1.workItem ORDER BY t1.CreatedDate) AS CreateDate_new
FROM 
    #Groups t1
LEFT JOIN 
    #Groups t2 ON t2.entity = t1.entity
                AND t2.workItem = t1.workItem
                AND t2.CreatedDate >= t1.CreatedDate
                AND (DATEDIFF(MINUTE, t1.CreatedDate, t2.CreatedDate) < 1)
GROUP BY 
    t1.entity, t1.workItem, t1.CreatedDate
ORDER BY 
    t1.workItem

最佳答案

我认为这被称为“间隙和岛屿”问题,我们在 SO 上有相当多的此类问题。

下面的方法是

  • 找到所有相距不超过 1 分钟的内容并将其分组
  • 然后从这些组中查找相关值。

这是执行此操作的一种方法

WITH Groups_Flagged AS
    (SELECT [Entity], [workItem], [CreatedDate],
            CASE WHEN DATEDIFF(second, LAG([CreatedDate], 1) OVER (PARTITION BY [Entity], [workItem] ORDER BY [CreatedDate]), [CreatedDate]) < 60 THEN 0 ELSE 1 END AS NewGrp_Flag
     FROM #Groups
    ),
Groups_Grouped AS
    (SELECT  [Entity], [workItem], [CreatedDate], SUM(NewGrp_Flag) OVER (ORDER BY [Entity], [workItem], [CreatedDate]) AS GrpNum
     FROM Groups_Flagged
     )
SELECT [Entity], [workItem], MAX([CreatedDate]) AS [CreatedDate]
FROM Groups_Grouped
GROUP BY [Entity], [workItem], [GrpNum]
ORDER BY [Entity], [workItem];

Groups_Flagged CTE 标记哪些记录是"new"记录,例如,不在该实体/工作项组合的上一条记录的 1 分钟(60 秒)内。它将新记录标记为“1”,其他记录标记为“0”。

然后,Groups_Grouped CTE 使用这些 1 和 0 的运行总和来为每个集群创建组编号。

最终选择按实体、工作项和新组编号进行分组,并获取这些组的最大 CreatedDate。

请注意,这将一系列事件视为一组(例如,如果您有 5 个创建者,所有这些都相距 50,则算作一个)。如果您不希望这种情况发生,则需要明确指定如何处理这些链。

(PS 感谢您提供创建数据的脚本 - 它使回答这些问题变得更加容易!)

关于sql-server - 如何按日期容限对记录进行分组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64547853/

相关文章:

sql-server - 在没有 MDS 的情况下部署 SQL 2008 R2 MDS 函数

sql - 为 SqlServer 查找表使用 tinyint 而不是 int 值得麻烦吗?

sql - 将 2 个日期行合并为 1 行中的 2 列

sql - 更新每个簇的最后一条记录

sql-server - 您可以调用返回记录集的 SQL 存储过程并将这些值加载到变量中吗?

sql-server - 如何在 MSSQL 中表示应用程序中的行和列?

sql-server - 如何在游标查询中使用 SQL 查询?

sql - 为什么SQL函数总是返回空结果集?

sql-server - list-distinct 中的最高值

sql-server - 将增量值插入表中