如何在时间跨度内对数据进行分组

use*_*149 5 gaps-and-islands

我有一组按日期排序的行,如下所示:

2017-01-01 
2017-01-01
2017-01-02
2017-01-03
2017-01-04
2017-01-17
2017-01-18
2017-01-18
2017-01-18
2017-01-19
2017-01-19
2017-01-26
2017-01-27
2017-01-27
Run Code Online (Sandbox Code Playgroud)

DDL & DML 为那些愿意提供帮助的人:

CREATE TABLE foo ( DateCol date );
INSERT INTO foo ( DateCol )
VALUES
  ( '2017-01-01' ),
  ( '2017-01-01' ),
  ( '2017-01-02' ),
  ( '2017-01-03' ),
  ( '2017-01-04' ),
  ( '2017-01-17' ),
  ( '2017-01-18' ),
  ( '2017-01-18' ),
  ( '2017-01-18' ),
  ( '2017-01-19' ),
  ( '2017-01-19' ),
  ( '2017-01-26' ),
  ( '2017-01-27' ),
  ( '2017-01-27' )
);
Run Code Online (Sandbox Code Playgroud)

我正在尝试对行进行分组并添加一个额外的列来标记该组。标准是,如果它们之间的时间间隔小于 3 天,则任意两行应在一组中,如下所示:

2017-01-01  A
2017-01-01  A
2017-01-02  A
2017-01-03  A
2017-01-04  A
2017-01-17  B
2017-01-18  B
2017-01-18  B
2017-01-18  B
2017-01-19  B
2017-01-19  B
2017-01-26  C
2017-01-27  C
2017-01-27  C
Run Code Online (Sandbox Code Playgroud)

如何做到这一点?

use*_*599 0

我建议分解问题,首先给出行和有序 id 并链接到以下日期,然后找到差异,然后找到差异何时大于 3 天的案例,并将行设置为 1 或 0。然后你应该能够对该列进行累积和以设置一个组。

CREATE TABLE #groupedDates(
[date] datetime,
[group] nvarchar(max))

INSERT INTO #groupedDates ([date], [group])
SELECT '2017-01-01', ''
UNION ALL
SELECT '2017-01-01', ''
UNION ALL
SELECT '2017-01-02', ''
UNION ALL
SELECT '2017-01-03', ''
UNION ALL
SELECT '2017-01-04', ''
UNION ALL
SELECT '2017-01-17', ''
UNION ALL
SELECT '2017-01-18', ''
UNION ALL
SELECT '2017-01-18', ''
UNION ALL
SELECT '2017-01-18', ''
UNION ALL
SELECT '2017-01-19', ''
UNION ALL
SELECT '2017-01-19', ''
UNION ALL
SELECT '2017-01-26', ''
UNION ALL
SELECT '2017-01-27', ''
UNION ALL
SELECT '2017-01-27', ''

SELECT [id],[startDate],[endDate], CASE WHEN [dif] <=3 THEN 0 ELSE 1 END [changeGroup]
INTO #tempA
FROM (
SELECT [start].[s] AS [id], [start].[date] AS [startDate], ISNULL([end].[date],[start].[date]) AS [endDate], 
ISNULL(DATEDIFF(dd,[start].[date],[end].[date]),0) AS [dif]
FROM (
SELECT [date] , ROW_NUMBER() OVER (ORDER BY [date]) AS [s]
FROM #groupedDates) AS [start]
LEFT OUTER JOIN (
SELECT [date] , ROW_NUMBER() OVER (ORDER BY [date]) - 1 AS [e]
FROM #groupedDates) AS [end]
ON [start].[s] = [end].[e]
) AS temp

SELECT [ta].[id], [ta].[startDate] AS [date], temp.[group]
FROM #tempA AS [ta]
INNER JOIN (
SELECT [t1].[id], SUM([t2].[changeGroup]) as [group]
FROM #tempA AS [t1]
INNER JOIN #tempA AS [t2] ON [t1].[id] >= [t2].[id]
GROUP BY [t1].[id], [t1].[changeGroup]) AS temp
ON [ta].[id] = temp.[id] + 1
ORDER BY [ta].[id]
Run Code Online (Sandbox Code Playgroud)

可能会有更好的方法来做到这一点,但我以前使用过这种方法