2009-10-19 29 views
58

dizisi döngüye alınması İşte benim senaryo:T-SQL: Bilinen değerlerin

en ı belirli kimlikleri bir dizi başka yordamını aramak için gereken bir saklı yordam var diyelim; Bunu yapmanın bir yolu var mı?

yani yerine bunu için gerek: Böyle bir şey yapmak

exec p_MyInnerProcedure 4 
exec p_MyInnerProcedure 7 
exec p_MyInnerProcedure 12 
exec p_MyInnerProcedure 22 
exec p_MyInnerProcedure 19 

:

*magic where I specify my list contains 4,7,12,22,19* 

DECLARE my_cursor CURSOR FAST_FORWARD FOR 
*magic select* 

OPEN my_cursor 
FETCH NEXT FROM my_cursor INTO @MyId 
WHILE @@FETCH_STATUS = 0 
BEGIN 

exec p_MyInnerProcedure @MyId 

FETCH NEXT FROM my_cursor INTO @MyId 
END 

Buradaki ana amaç idame basitçe (kolay kaldırmak için/iş değişiklikleri gibi kimliklerini ekleyin) Tüm kimliklerin tek bir satırda listelenebilmesi ... Performansın bir sorun kadar büyük olmaması gerekir

+0

SQL Server sürümü nedir? –

+0

ile ilgili, eğer varchars gibi tamsayı olmayan bir liste üzerinde, imlecin bulunduğu bir çözümde yinelemeniz gerekiyorsa: [ste-in-a-list-in-sql-in-sql-server] (https://stackoverflow.com/questions)/38388144/sql-in-a-list-in-a-dizeleri-sql-sunucu) – Pac0

cevap

74
declare @ids table(idx int identity(1,1), id int) 

insert into @ids (id) 
    select 4 union 
    select 7 union 
    select 12 union 
    select 22 union 
    select 19 

declare @i int 
declare @cnt int 

select @i = min(idx) - 1, @cnt = max(idx) from @ids 

while @i < @cnt 
begin 
    select @i = @i + 1 

    declare @id = select id from @ids where idx = @i 

    exec p_MyInnerProcedure @id 
end 
+0

ayrımını yapmak için düzenledim, daha zarif bir yol olacağını umuyordum, ama bence bu, alabildiğim kadar yakın olacak: Burada seçme/birlikler arasında bir melez kullanarak sona erdi ve imleci buradan örnek. Teşekkürler! – John

+11

@john: 2008'i kullanıyorsanız, INSERT @ids VALUES (4), (7), (12), (22), (19) –

+2

Sadece FYI gibi bir şey yapabilirsiniz, bunun gibi bellek tabloları genellikle daha hızlıdır imleçlerden (5 değer için olsa da, herhangi bir fark yarattığını pek göremiyorum), ama onları sevdiğim en büyük neden, uygulama kodunda bulacağınız şeye benzeyen sözdizimini bulmamdır, oysa imleçler (benim için) nispeten farklı. –

33

Bu senaryoda yaptığım şey, Ids'ı tutmak için bir tablo değişkeni oluşturmaktır.

Declare @Ids Table (id integer primary Key not null) 
    Insert @Ids(id) values (4),(7),(12),(22),(19) 

- (veya bu tabloyu oluşturmak için başka tablo değerli işlev çağrısı)

O zaman bu tabloya

Declare @Id Integer 
    While exists (Select * From @Ids) 
    Begin 
     Select @Id = Min(id) from @Ids 
     exec p_MyInnerProcedure @Id 
     Delete from @Ids Where id = @Id 
    End 

veya satır ... dayanan döngü

Declare @Id Integer = 0 -- assuming all Ids are > 0 
    While exists (Select * From @Ids 
       where id > @Id) 
    Begin 
     Select @Id = Min(id) 
     from @Ids Where id > @Id 
     exec p_MyInnerProcedure @Id 
    End 

Yukarıdaki yaklaşımlardan herhangi biri, bir imleçten (normal Kullanıcı Tablosu/Tabloları ile bildirilmiş) daha hızlıdır. Tablo değerli değişkenler, hatalı kullanıldığında (çok sayıda satır içeren çok geniş tablolar için) performans göstermedikleri için kötü bir geri dönüşüme sahiptir. Ancak bunları yalnızca bir anahtar değeri veya 4 baytlık bir tamsayı tutmak için kullanıyorsanız, bir dizinle (bu durumda olduğu gibi) son derece hızlıdırlar.

+0

Yukarıdaki yaklaşım, bir tablo değişkeninde bildirilen bir imleç ile eşdeğer veya daha yavaştır. Bu kesinlikle daha hızlı değil. Yine de, normal kullanıcı tablolarında w/varsayılan seçenek olarak bildirilen bir imleçten daha hızlı olacaktır. –

+0

@Peter, ahhh, evet doğru, hatalı bir imleç kullanarak düzenli bir kullanıcı tablosu, bir tablo değişkeni ima eder varsayalım .. –

14

kullanımı statik imleç değişken ve split function:

declare @comma_delimited_list varchar(4000) 
set @comma_delimited_list = '4,7,12,22,19' 

declare @cursor cursor 
set @cursor = cursor static for 
    select convert(int, Value) as Id from dbo.Split(@comma_delimited_list) a 

declare @id int 
open @cursor 
while 1=1 begin 
    fetch next from @cursor into @id 
    if @@fetch_status <> 0 break 
    ....do something.... 
end 
-- not strictly necessary w/ cursor variables since they will go out of scope like a normal var 
close @cursor 
deallocate @cursor 

imleçler yükü bir sürü oluşturabilir kullanıcı tabloları karşı bildirilmiş varsayılan seçenekleri beri kötü bir temsilcisi var.

Ancak bu durumda, buradaki diğer tüm yöntemlerden daha az olan yük asgari düzeyde. STATIC, SQL Server'a sonuçları tempdb'de sonuçlandırmasını ve ardından bunu yinelemesini söyler. Bunun gibi küçük listeler için en uygun çözümdür.

4

Ben genellikle Sen aşağıda deneyebilirsiniz aşağıdaki yaklaşımdır

DECLARE @calls TABLE (
    id INT IDENTITY(1,1) 
    ,parameter INT 
    ) 

INSERT INTO @calls 
select parameter from some_table where some_condition -- here you populate your parameters 

declare @i int 
declare @n int 
declare @myId int 
select @i = min(id), @n = max(id) from @calls 
while @i <= @n 
begin 
    select 
     @myId = parameter 
    from 
     @calls 
    where id = @i 

     EXECUTE p_MyInnerProcedure @myId 
    set @i = @i+1 
end 
2
CREATE TABLE #ListOfIDs (IDValue INT) 

DECLARE @IDs VARCHAR(50), @ID VARCHAR(5) 
SET @IDs = @OriginalListOfIDs + ',' 

WHILE LEN(@IDs) > 1 
BEGIN 
SET @ID = SUBSTRING(@IDs, 0, CHARINDEX(',', @IDs)); 
INSERT INTO #ListOfIDs (IDValue) VALUES(@ID); 
SET @IDs = REPLACE(',' + @IDs, ',' + @ID + ',', '') 
END 

SELECT * 
FROM #ListOfIDs 
1

kullanın:

declare @list varchar(MAX), @i int 
select @i=0, @list ='4,7,12,22,19,' 

while(@i < LEN(@list)) 
begin 
    declare @item varchar(MAX) 
    SELECT @item = SUBSTRING(@list, @i,CHARINDEX(',',@list,@i)[email protected]) 
    select @item 

    --do your stuff here with @item 
    exec p_MyInnerProcedure @item 

    set @i = CHARINDEX(',',@list,@i)+1 
    if(@i = 0) set @i = LEN(@list) 
end 
+2

Bu liste bildirimini şöyle yapardım: '@list = '4,7,12,22,19' + ','' - bu yüzden listenin bir virgülle bitmesi gerektiği tamamen açıktır. onsuz çalışın!). –