运行SQL Server 2016 Express。
我有这个包含样本数据的表:
ID Datetime2 other columns
------------------------------------------
1 2017-01-14 11:00:00 ...
1 2017-01-14 11:01:00 ...
1 2017-01-14 11:02:00 ...
1 2017-01-14 11:03:00 ...
1 2017-01-14 11:10:00 ... --> 7 minutes gap
1 2017-01-14 11:11:00 ...
1 2017-01-14 11:20:00 ... --> 9 minutes gap
1 2017-01-14 11:22:00 ...
1 2017-01-14 11:24:00 ...
我希望得到这样的结果
ID start end other columns
-----------------------------------------------------------
1 2017-01-14 11:00 2017-01-14 11:03 ...
1 2017-01-14 11:10 2017-01-14 11:11 ...
1 2017-01-14 11:20 2017-01-14 11:24 ...
当我们在当前行日期时间值与下一行日期时间值之间有5或X分钟或更长的间隔时,我必须创建一个新组。
我有这样的查询,但是当它有5分钟或更长的间隔时,我无法弄清楚将行分组到何处。
WITH groups(DateTimeField, grp) AS
(
SELECT DISTINCT
DateTimeField,
DATEDIFF(MINUTE, DateTimeField, lag(DateTimeField) OVER (ORDER BY DateTimeField DESC)) grp
FROM
MyTable
WHERE
ID = 1
)
SELECT
COUNT(*) AS consecutiveDates,
MIN(DateTimeField) AS minDate,
MAX(DateTimeField) AS maxDate
FROM
groups
GROUP BY
grp
ORDER BY
1 DESC, 2 DESC
致以最诚挚的问候,
答案 0 :(得分:1)
首先进行测试我已经生成了一些随机日期:
DECLARE @DatesTables TABLE (ID INT, [DateTime2] DATETIME)
DECLARE @ID INT
DECLARE @Date DATETIME
SET @Date = GETDATE()
WHILE (SELECT COUNT(*) FROM @DatesTables) < 50
BEGIN
SET @ID = (SELECT COUNT(*) FROM @DatesTables) + 1
SET @Date = DATEADD(MINUTE, rand() * 7 + 1,@Date)
INSERT INTO @DatesTables (ID, [DateTime2]) VALUES (@ID, @Date)
END
现在让我们计算每行和下一行之间的差异,并确定我们的组应该从哪里开始:
DECLARE @DatesTables2 TABLE ([NewID] INT, [DateA] DATETIME, [DateB] DATETIME, DiffMin INT, [Break] INT)
INSERT INTO @DatesTables2
SELECT
ROW_NUMBER() OVER (ORDER BY a.ID),
a.DateTime2 AS DateA,
b.DateTime2 AS DateB,
DATEDIFF(MINUTE, a.[DateTime2], b.[DateTime2]) AS DiffMin,
CASE WHEN DATEDIFF(MINUTE, a.[DateTime2], b.[DateTime2]) > 5 THEN 1 ELSE 0 END AS [Break]
FROM @DatesTables a JOIN @DatesTables b ON a.id = b.ID - 1
通过将中断数相加来为每一行分配一组:
DECLARE @Groups TABLE (DateA DATETIME, DateB DATETIME, DiffMin INT, [Break] INT, [Group] INT)
INSERT INTO @Groups
SELECT a.DateA, a.DateB,a.DiffMin, a.[Break], SUM(b.[Break]) + a.[Break] AS [Group] FROM @DatesTables2 a JOIN @DatesTables2 b
ON b.newid < a.newid
GROUP BY a.DateA, a.DateB, a.[Break],a.DiffMin
最后选择您的分组结果:
SELECT [Group], MIN(DateA) AS Start, MAX(DateB) AS [End] FROM @Groups GROUP BY [Group] ORDER BY [Group]
虽然我已经使用表变量来更容易理解,但您可以使用子查询。
答案 1 :(得分:0)
感谢@apc。修改代码以添加滞后函数而不是连接并删除[Break]&lt;&gt; 0
中的行//..
--use of the lag function
INSERT INTO @DatesTables2
SELECT
ROW_NUMBER() OVER (ORDER BY a.DateTime2 DESC),
a.DateTime2 AS DateA,
lag(DateTime2 ) OVER (ORDER BY DateTime2 DESC) AS DateB,
DATEDIFF(MINUTE, a.DateTime2 , lag(DateTime2 ) OVER (ORDER BY DateTime2 DESC)) AS DiffMin,
CASE WHEN DATEDIFF(MINUTE, a.DateTime2 , lag(DateTime2 ) OVER (ORDER BY DateTime2 DESC)) > 5 THEN 1 ELSE 0 END AS [Break]
FROM DatesTables a
//..
--Query only where [Break=0] to discard the end value where the gap is more than 5 minutes.
INSERT INTO @Groups
SELECT a.DateA, a.DateB, a.DiffMin, a.[Break], SUM(b.[Break]) + a.[Break] AS [Group]
FROM @DatesTables2 a JOIN @DatesTables2 b ON b.newid < a.newid
WHERE a.[Break] = 0
GROUP BY a.DateA, a.DateB, a.[Break], a.DiffMin
//..
--Finally get the datetime diff between min and max.
SELECT [Group], MIN(DateA) AS Start, MAX(DateB) AS [End], DATEDIFF(MINUTE, MIN(DateA), MAX(DateB))
FROM @Groups
GROUP BY [Group]
ORDER BY [Group]