SQL 状态随开始日期和结束日期而变化
Posted
技术标签:
【中文标题】SQL 状态随开始日期和结束日期而变化【英文标题】:SQL status changes with start and end dates 【发布时间】:2021-11-25 10:50:17 【问题描述】:这是 2021 年 9 月 1 日至 2021 年 9 月 10 日期间用户状态的表格。 1
表示“活跃”。 0
表示“已取消”。
date | user | status |
---|---|---|
9/1/2021 | 1 | 1 |
9/1/2021 | 2 | 0 |
9/1/2021 | 3 | 1 |
9/2/2021 | 1 | 1 |
9/2/2021 | 2 | 1 |
9/2/2021 | 3 | 1 |
9/3/2021 | 1 | 0 |
9/3/2021 | 2 | 1 |
9/3/2021 | 3 | 1 |
9/4/2021 | 1 | 0 |
9/4/2021 | 2 | 1 |
9/4/2021 | 3 | 1 |
9/5/2021 | 1 | 0 |
9/5/2021 | 2 | 1 |
9/5/2021 | 3 | 0 |
9/6/2021 | 1 | 1 |
9/6/2021 | 2 | 1 |
9/6/2021 | 3 | 0 |
9/7/2021 | 1 | 1 |
9/7/2021 | 2 | 1 |
9/7/2021 | 3 | 0 |
9/8/2021 | 1 | 0 |
9/8/2021 | 2 | 1 |
9/8/2021 | 3 | 1 |
9/9/2021 | 1 | 0 |
9/9/2021 | 2 | 1 |
9/9/2021 | 3 | 1 |
9/10/2021 | 1 | 1 |
9/10/2021 | 2 | 0 |
9/10/2021 | 3 | 1 |
我想获取在此期间每个用户的活动和取消时段的开始和结束日期。我知道这涉及到一个窗口函数,但我不知道该怎么做。这是我想要的输出:
user | status | start date | end date |
---|---|---|---|
1 | 1 | 9/1/2021 | 9/2/2021 |
1 | 0 | 9/3/2021 | 9/5/2021 |
1 | 1 | 9/6/2021 | 9/7/2021 |
1 | 0 | 9/8/2021 | 9/9/2021 |
1 | 1 | 9/10/2021 | 9/10/2021 |
2 | 0 | 9/1/2021 | 9/1/2021 |
2 | 1 | 9/2/2021 | 9/9/2021 |
2 | 0 | 9/10/2021 | 9/10/2021 |
3 | 1 | 9/1/2021 | 9/4/2021 |
3 | 0 | 9/5/2021 | 9/7/2021 |
3 | 1 | 9/8/2021 | 9/10/2021 |
【问题讨论】:
不会按开始日期订购,状态工作? 【参考方案1】:更新
这里是一个例子:fiddle
更新的查询,
;with cte as (
SELECT *,Rank() OVER ( partition by usr,status order by dt )as rnk
,LAG(dt,1) OVER (partition by usr order by dt desc) as LAG
,Row_number() over (partition by usr order by dt asc) as rnum
,count(*) over (partition by usr,status) as cnt
FROM TABLE1
)
Select usr,status,dt as start_date,LAG as End_date from cte
【讨论】:
嗯,当用户在取消后再次变得活跃时,这似乎没有捕捉到。如果用户活动或取消仅一天,它也不会返回正确的结束日期。 @bbk611 我更新了答案。我想,现在运行,你是如何描述它的。 那也行不通。在您的示例表中,每个用户的状态,无论是活动还是取消,都只占用一行。在我提供的表格中,每个用户有时会在超过一天的时间内处于活跃或取消状态。所以他们的状态有时会占据不止一排。【参考方案2】:我想通了。
关键组件在当前状态不等于先前状态时进行过滤。这表示用户状态更改的日期。
当您过滤这些行时,您只需使用 LEAD()
窗口函数并减去 1 天即可获得该状态的结束日期。
with win as
(
select
usr
, dt
, lag(status) over (partition by usr order by dt) as prev_status
, status
from subs
)
select
usr
, status
, dt as start_date
, coalesce(lead(dt) over (partition by usr order by dt) - interval '1 day', (select max(dt) from win)) as end_date
from win
where
status <> prev_status
or prev_status is null
【讨论】:
以上是关于SQL 状态随开始日期和结束日期而变化的主要内容,如果未能解决你的问题,请参考以下文章
SQL 'overlaps' 仅获取开始和结束之间的日期(不包括开始和结束日期)
如果开始日期和结束日期跨越一个或多个月,则插入表格时日期格式会发生变化
如何通过在 SQL Server 中选择周数来获取开始日期和结束日期