SQL 中的相干间隔?
Coherent intervals in SQL?
考虑一个简单的日记 table:
Date Mood
---- ----
1 Good
2 Good
3 Good
4 Bad
5 Bad
6 Good
我对情绪间隔感兴趣,因此我会得到这样的结果:
Mood BeginDate EndDate
---- --------- -------
Good 1 3
Bad 4 5
Good 6 6
在 SQL 中可以不使用迭代吗?
如果从每种心情的开始日期中减去一个序列号,当值相邻时,您将得到一个常数:
Date Mood Seqnum
1 Good 1
2 Good 2
3 Good 3
4 Bad 1
5 Bad 2
6 Good 4
然后你可以使用聚合来做你想做的事。如果 date
真的是一个数字:
select mood, min(date), max(date)
from (select t.*,
row_number() over (partition by mood order by date) as seqnum
from t
) t
group by mood, (date - seqnum);
如果date
真的是date
:
select mood, min(date), max(date)
from (select t.*,
row_number() over (partition by mood order by date) as seqnum
from t
) t
group by mood, dateadd(day, - seqnum, date)
在 Gordon Linoff 的回答中回应这条评论:
If date
is really a number:
如果不是怎么办?只要稍作调整,您还有前进的道路。
WITH d AS (
SELECT * FROM (VALUES
(cast('2021-04-22 00:00' as datetime2(0)), 'Good'),
(cast('2021-04-22 00:05' as datetime2(0)), 'Good'),
(cast('2021-04-22 00:07' as datetime2(0)), 'Good'),
(cast('2021-04-22 00:10' as datetime2(0)), 'Bad'),
(cast('2021-04-22 00:25' as datetime2(0)), 'Bad'),
(cast('2021-04-22 01:43' as datetime2(0)), 'Good')
) AS x([date], mood)
), t AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY [date]) AS a,
ROW_NUMBER() OVER (PARTITION BY mood ORDER BY [date]) AS seqnum
FROM d
)
select mood, min(date), max(date)
from t
group by mood, a - seqnum
order by min(date)
分解一下,第一个 cte 只是您的数据,但现在 date
使用日期时间列而不是整数。请注意,连续行之间的间隔不是恒定的(它可以是,但我这样做是为了表明它 不需要 是)。从那里,我们使用 row_number()
函数计算两个值 - 一个枚举整个集合,另一个按情绪划分。其余的(在精神上)与戈登的回答相同。
考虑一个简单的日记 table:
Date Mood
---- ----
1 Good
2 Good
3 Good
4 Bad
5 Bad
6 Good
我对情绪间隔感兴趣,因此我会得到这样的结果:
Mood BeginDate EndDate
---- --------- -------
Good 1 3
Bad 4 5
Good 6 6
在 SQL 中可以不使用迭代吗?
如果从每种心情的开始日期中减去一个序列号,当值相邻时,您将得到一个常数:
Date Mood Seqnum
1 Good 1
2 Good 2
3 Good 3
4 Bad 1
5 Bad 2
6 Good 4
然后你可以使用聚合来做你想做的事。如果 date
真的是一个数字:
select mood, min(date), max(date)
from (select t.*,
row_number() over (partition by mood order by date) as seqnum
from t
) t
group by mood, (date - seqnum);
如果date
真的是date
:
select mood, min(date), max(date)
from (select t.*,
row_number() over (partition by mood order by date) as seqnum
from t
) t
group by mood, dateadd(day, - seqnum, date)
在 Gordon Linoff 的回答中回应这条评论:
If
date
is really a number:
如果不是怎么办?只要稍作调整,您还有前进的道路。
WITH d AS (
SELECT * FROM (VALUES
(cast('2021-04-22 00:00' as datetime2(0)), 'Good'),
(cast('2021-04-22 00:05' as datetime2(0)), 'Good'),
(cast('2021-04-22 00:07' as datetime2(0)), 'Good'),
(cast('2021-04-22 00:10' as datetime2(0)), 'Bad'),
(cast('2021-04-22 00:25' as datetime2(0)), 'Bad'),
(cast('2021-04-22 01:43' as datetime2(0)), 'Good')
) AS x([date], mood)
), t AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY [date]) AS a,
ROW_NUMBER() OVER (PARTITION BY mood ORDER BY [date]) AS seqnum
FROM d
)
select mood, min(date), max(date)
from t
group by mood, a - seqnum
order by min(date)
分解一下,第一个 cte 只是您的数据,但现在 date
使用日期时间列而不是整数。请注意,连续行之间的间隔不是恒定的(它可以是,但我这样做是为了表明它 不需要 是)。从那里,我们使用 row_number()
函数计算两个值 - 一个枚举整个集合,另一个按情绪划分。其余的(在精神上)与戈登的回答相同。