這是一個相當典型的範圍尋找問題,引入了級聯。不確定以下幾點是否完全吻合,但這是一個起點。 (遊標通常是最好的避免,除了小於一組的情況下,它們比基於集合的解決方案更快,所以在遊標討厭之前請注意我在這裏使用遊標,因爲這對我來說像一個友好的遊標。問題 - 我通常避免他們)
所以,如果我創建的數據是這樣的:
CREATE TABLE [dbo].[sourceValues](
[Start] [int] NOT NULL,
[End] [int] NOT NULL,
[Item] [varchar](100) NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[sourceValues] WITH CHECK ADD CONSTRAINT [End_after_Start] CHECK (([End]>[Start]))
GO
ALTER TABLE [dbo].[sourceValues] CHECK CONSTRAINT [End_after_Start]
GO
declare @i int; set @i = 0;
declare @start int;
declare @end int;
declare @item varchar(100);
while @i < 1000
begin
set @start = ABS(CHECKSUM(newid()) % 100) + 1 ; -- "random" int
set @end = @start + (ABS(CHECKSUM(newid()) % 10)) + 2; -- bigger random int
set @item = char((ABS(CHECKSUM(newid())) % 5) + 65); -- random letter A-E
print @start; print @end; print @item;
insert into sourceValues(Start, [End], Item) values (@start , @end, @item);
set @i += 1;
end
然後我可以把這樣的問題:每一個「開始」,每個「結束」值表示的改變在當前Items的集合中,在某個時間添加一個或刪除一個。在下面的代碼中,我把這個概念與「事件」混爲一談,意思是添加或刪除。每個開始或結束都像是一個時間,所以我使用術語「打勾」。如果我按照事件時間(開始和結束)排序的所有事件的集合,我可以遍歷所有事件,同時保持所有正在運行的項目在內存表中的運行計數。每次刻度值的變化,我拿這一紀錄的快照:
declare @tick int;
declare @lastTick int;
declare @event varchar(100);
declare @item varchar(100);
declare @concatList varchar(max);
declare @currentItemsList table (Item varchar(100));
create table #result (Start int, [End] int, Items varchar(max));
declare eventsCursor CURSOR FAST_FORWARD for
select tick, [event], item from (
select start as tick, 'Add' as [event], item from sourceValues as adds
union all
select [end] as tick, 'Remove' as [event], item from sourceValues as removes
) as [events]
order by tick
set @lastTick = 1
open eventsCursor
fetch next from eventsCursor into @tick, @event, @item
while @@FETCH_STATUS = 0
BEGIN
if @tick != @lastTick
begin
set @concatList = ''
select @concatList = @concatlist + case when len(@concatlist) > 0 then '-' else '' end + Item
from @currentItemsList
insert into #result (Start, [End], Items) values (@lastTick, @tick, @concatList)
end
if @event = 'Add' insert into @currentItemsList (Item) values (@item);
else if @event = 'Remove' delete top (1) from @currentItemsList where Item = @item;
set @lastTick = @tick;
fetch next from eventsCursor into @tick, @event, @item;
END
close eventsCursor
deallocate eventsCursor
select * from #result order by start
drop table #result
使用光標這種特殊情況下允許只有一個「通」,通過數據,如運行總計問題。 Itzik Ben-Gan在他的SQL 2005書籍中有一些很好的例子。
您運行的是哪個版本的SQL Server? – Sung 2009-08-01 16:27:11
有多少物品可能重疊? (也就是說它總是2,a和b,或者它可能是任何數字?) – onupdatecascade 2009-08-01 18:44:16