SQL 状态随开始日期和结束日期而变化
SQL status changes with start and end dates
这是 2021 年 9 月 1 日至 2021 年 9 月 10 日期间的 table 用户状态。 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
我想获取这段时间内每个用户的活动和取消时段的开始和结束日期。我知道这涉及到 window 函数,但我不太清楚该怎么做。这是我想要的输出:
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
已更新
这里有一个例子: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
我想通了。
当当前状态不等于先前状态时,关键组件正在过滤。表示用户状态变化的日期。
过滤这些行时,您只需使用 LEAD()
window 函数并减去 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
这是 2021 年 9 月 1 日至 2021 年 9 月 10 日期间的 table 用户状态。 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 |
我想获取这段时间内每个用户的活动和取消时段的开始和结束日期。我知道这涉及到 window 函数,但我不太清楚该怎么做。这是我想要的输出:
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 |
已更新
这里有一个例子: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
我想通了。
当当前状态不等于先前状态时,关键组件正在过滤。表示用户状态变化的日期。
过滤这些行时,您只需使用 LEAD()
window 函数并减去 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