我有这样的表格行。
status start end
32 1/1/2017 1/2/2017
32 1/2/2017 4/2/2017
1 4/2/2017 6/3/2017
1 6/3/2017 9/5/2017
32 9/5/2017 19/5/2017
32 19/5/2017 22/6/2017
我想把行分组到
status start end
32 1/1/2017 4/2/2017
1 4/2/2017 9/5/2017
32 9/5/2017 22/6/2017
我该如何使用SQL?
谢谢你的帮助。
答案 0 :(得分:1)
我认为你不能一步一步地做到这一点。也许如果你采用一些丑陋的递归CTE或一长串CTE或嵌套子查询。基本上,您需要重新配置数据集,以便了解期间的开始和结束。
假设:
我将使用SQL-Server语法,因为它是我最熟悉的,但这些操作应该是你可以在大多数sql环境中做一些修改的事情。 (我使用临时表和CTE,但您可以使用子查询)
create table dbo.[Status] (
[status] int,
[start] date,
[end] date
)
insert into dbo.[Status] ([status], [start], [end])
values
(32, '20170101', '20170201'),
(32, '20170201', '20170204'),
(1, '20170204', '20170306'),
(1, '20170306', '20170509'),
(32, '20170509', '20170519'),
(32, '20170519', '20170622')
create table dbo.Result (
PeriodID int identity, -- to make grouping and self-referential joins easier
Status int,
start date,
next_start date null,
[end] date null
)
select * from dbo.[Status]
-- This will get you all the periods and their start dates
;with cteExcludeTheseRows(status, start) as (
-- These are the records where the Start date matches an end date for the same status group. As a result these aren't real periods, just extensions.
select S.status, S.start
from [Status] S
join [Status] Prior on S.Status = Prior.status and S.start = Prior.[end]
)
insert into dbo.Result (status, start)
select
S.status,
S.start
from [Status] S
left join cteExcludetheserows Exclude on S.status = Exclude.status and S.start = Exclude.start
where Exclude.status is null
-- Reference the temp table to get the next start period for your status groups, that way you know that the end date for that period has to be less then that date
;with cteNextStart (PeriodID, next_start) as (
select
R.PeriodID,
next_start = min(next.start)
from dbo.Result R
join dbo.Result next on R.status = next.status and r.start < next.start
group by R.PeriodID
)
update R
set R.next_start = next.next_start
from dbo.Result R
join cteNextStart next on R.PeriodID = next.PeriodID
-- Now get the end date for each period by looking back at your main status table
;with cteEnd (PeriodID, [end]) as (
select
R.PeriodID,
[end] = max(s.[end])
from dbo.Result R
join [Status] S on R.status = s.status and S.[end] between R.start and isnull(R.next_start, '99991231')
group by R.PeriodID
)
update R
set R.[end] = [end].[end]
from dbo.Result R
join cteEnd [end] on R.PeriodID = [end].PeriodID
-- And finally, here you have your result set
select
status,
start,
[end]
from dbo.Result
order by start, status
drop table dbo.[Status]
drop table dbo.Result
答案 1 :(得分:1)
另见 demo
SELECT * FROM aaa a
where a.sstatus != (select top 1 b.sstatus from aaa b
where b.start_date < a.start_date
order by b.start_date desc);
答案 2 :(得分:0)
Object.getPrototypeOf(d)