需要群组和群岛的T-SQL查询

时间:2014-04-29 14:24:50

标签: sql-server sql-server-2008 tsql gaps-and-islands

create table #sample (rowguid int identity ,id_frm int ,id_to int)

insert into #sample values( 1,5)
insert into #sample values( 7,13)
insert into #sample values( 17,20) 

在上表中,我的值为Id和Ending Id。我需要准备一个表,其中所有数字都在起始标识和结束标识之间

我已经尝试过循环,但在现实世界中反应非常慢。

任何身体帮我查询???

这是我到目前为止所尝试的......

declare @sql varchar(8000)  = '  
select top '+cast((select  max(id_to) from #sample) as varchar(100))+' identity(int,1,1) as guidid into  tally from sysobjects,syscolumns '

exec (@sql)


alter table Tally add slab varchar(10)

create clustered index  idx on Tally(guidid)
create  clustered index  idx on #sample(id_frm asc,id_to desc)

update Tally set slab = rowguid 
from #sample join Tally on guidid between id_frm and id_to 

delete from Tally where slab is null

select * from Tally

此查询适用于小数

但我的实时时间表有13位数字。它通过算术溢出错误

2 个答案:

答案 0 :(得分:3)

假设范围id_frmid_to是相对较小的整数,例如< 1M,解决此问题的一种方法是创建一个包含范围内所有值并加入它的表:

WITH lotsOfNumbers AS
(
   SELECT ROW_NUMBER() OVER (ORDER BY o1.object_id) AS id
   FROM sys.objects o1 CROSS JOIN sys.objects o2 
)
INSERT INTO #targetTable
SELECT l.ID
   FROM lotsOfNumbers l
   INNER JOIN #sample
   ON l.ID BETWEEN #sample.id_frm AND #sample.id_to;

SqlFiddle here

具有必要ID范围的永久表和ID上的聚簇索引显然会提高性能。

如果您的范围重叠,请添加DISTINCT,并且您不希望在结果中出现重复项。

答案 1 :(得分:-2)

如果您能够在另一个表中获得全范围的可接受值,则可以在不循环的情况下使用它。下面的meathod得到最小值(1)和最大值(20),名为#range的临时表将返回介于两者之间的所有内容。

drop table #sample
drop table #range 

create table #sample (id_frm int ,id_to int)

insert into #sample values( 1,5)
insert into #sample values( 7,13)
insert into #sample values( 17,20) 



create table #range (id  int)



insert into #range select 1
go

insert into #range   select top 1 max(id)+ 1   from #range  
go 100

declare @min int
declare @max int

set @min= (select min(id_frm ) from #sample )
set @max =  (select   max(id_to) from #sample )
select * from #range where id between @min and @max