2012-08-07 2 views
47

j'exécuter une requête select @id=table.id from table et je dois boucler sur les résultats afin que je puisse exec une procédure de magasin pour chaque ligne exec stored_proc @[email protected],@otherVarName='test'boucle T-SQL sur des résultats de requête

Comment puis-je faire cela dans un script T-SQL?

+0

bien, je ne l'ai pas essayé quoi que ce soit. Je ne sais pas comment le faire. Je suppose que je pourrais essayer d'écrire une boucle de style 'C', mais je doute que cela fonctionne. Peut-être une boucle de style "PHP", mais encore une fois, je doute que cela fonctionne aussi. J'ai besoin de tout faire en T-SQL en ce que je peux exécuter le SQL dans SMS sans langage externe faisant la boucle ... Hense la question en premier lieu. – Justin808

+1

@Shedal L'ironie de ces commentaires/réponses (bien que moins que les réponses "google it") est que, au fil du temps, ils ont tendance à devenir les meilleurs résultats google. Ainsi, lorsque quelqu'un cherche une solution au problème, la première chose qu'il va rencontrer est un dénigrement (habituellement justifié) de quelqu'un d'autre qui a eu le problème, mais qui n'a pas pris la peine de chercher la réponse lui-même. À long terme, cela devient ennuyeux pour les gens qui essaient réellement de chercher la réponse. – jahu

+0

@MarcinHabuszewski bien, pour être honnête, dans le cas où il n'y a pas de réponse appropriée à une question commune, il n'apparaîtra pas sur la première page des résultats de recherche Google. Normalement. –

Répondre

124

Vous pouvez utiliser un curseur dans ce cas:

DECLARE @id INT 
DECLARE @name NVARCHAR(100) 
DECLARE @getid CURSOR 

SET @getid = CURSOR FOR 
SELECT table.id, 
     table.name 
FROM table 

OPEN @getid 
FETCH NEXT 
FROM @getid INTO @id, @name 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    EXEC stored_proc @[email protected], @otherVarName='test', @[email protected] 
    FETCH NEXT 
    FROM @getid INTO @id, @name 
END 

CLOSE @getid 
DEALLOCATE @getid 

modifié pour afficher plusieurs paramètres de la table.

+1

Que faire si vous voulez obtenir plus de ID de la table? –

+2

@HenleyChiu J'ai modifié la réponse pour inclure un nouveau paramètre '@ name' qui, je crois, fonctionnera, mais cela fait un moment que j'ai utilisé un curseur maintenant! – XN16

+0

@ XN16 en utilisant plus de ID n'a pas fonctionné, contourner le problème :-( –

12

Vous pouvez faire quelque chose comme ceci:

create procedure test 
as 
BEGIN 

    create table #ids 
    (
     rn int, 
     id int 
    ) 

    insert into #ids (rn, id) 
    select distinct row_number() over(order by id) as rn, id 
    from table 

    declare @id int 
    declare @totalrows int = (select count(*) from #ids) 
    declare @currentrow int = 0 

    while @currentrow < @totalrows 
    begin 
     set @id = (select id from #ids where rn = @currentrow) 

     exec stored_proc @[email protected], @otherVarName='test' 

     set @currentrow = @currentrow +1 
    end 

END 
+0

J'aime mieux cette méthode puisque le curseur est plus lent que pendant la boucle –

+2

Les curseurs sont plus lents par rapport aux opérations de réglage (c.-à-d. mise à jour de déclaration) .Si vous comparez à la création d'une table temporaire et de faire quelques _writes_, je ne suis pas si sûr.Voir http://www.techrepublic.com/blog/the-enterprise-cloud/comparing-cursor-vs-while-loop- performance-in-sql-server-2008/ J'ai fait mes propres tests et je suis d'accord Probablement une table temporaire est plus rapide quand vous avez des problèmes de verrouillage et vous pouvez obtenir votre sous-ensemble plus rapidement et ensuite le traiter. . –

6

Ma préfèrent solution Microsoft KB 111401 http://support.microsoft.com/kb/111401.

Le lien fait référence à 3 exemples:

Cet article décrit différentes méthodes que vous pouvez utiliser pour simuler une logique de curseur comme FETCH NEXT dans une procédure stockée, déclencheur ou batch Transact-SQL.

/********** example 1 **********/ 

declare @au_id char(11) 

set rowcount 0 
select * into #mytemp from authors 

set rowcount 1 

select @au_id = au_id from #mytemp 

while @@rowcount <> 0 
begin 
    set rowcount 0 
    select * from #mytemp where au_id = @au_id 
    delete #mytemp where au_id = @au_id 

    set rowcount 1 
    select @au_id = au_id from #mytemp<BR/> 
end 
set rowcount 0 



/********** example 2 **********/ 

declare @au_id char(11) 

select @au_id = min(au_id) from authors 

while @au_id is not null 
begin 
    select * from authors where au_id = @au_id 
    select @au_id = min(au_id) from authors where au_id > @au_id 
end 



/********** example 3 **********/ 

set rowcount 0 
select NULL mykey, * into #mytemp from authors 

set rowcount 1 
update #mytemp set mykey = 1 

while @@rowcount > 0 
begin 
    set rowcount 0 
    select * from #mytemp where mykey = 1 
    delete #mytemp where mykey = 1 
    set rowcount 1 
    update #mytemp set mykey = 1 
end 
set rowcount 0 
0

essayez ceci:

declare @i tinyint = 0, 
    @count tinyint, 
    @id int, 
    @name varchar(max) 

select @count = count(*) from table 
while (@i < @count) 
begin 
    select @id = id, @name = name from table 
    order by nr asc offset @i rows fetch next 1 rows only 

    exec stored_proc @varName = @id, @otherVarName = 'test', @varForName = @name 

    set @i = @i + 1 
end 
1
DECLARE @id INT 
DECLARE @name NVARCHAR(100) 
DECLARE @getid CURSOR 

SET @getid = CURSOR FOR 
SELECT table.id, 
     table.name 
FROM table 

WHILE 1=1 
BEGIN 

    FETCH NEXT 
    FROM @getid INTO @id, @name 
    IF @@FETCH_STATUS < 0 BREAK 

    EXEC stored_proc @[email protected], @otherVarName='test', @[email protected] 

END 

CLOSE @getid 
DEALLOCATE @getid