J'ai une relation parent-enfant dans la base de données. Ce que je dois faire, c'est une boucle à travers la requête du parent et utiliser la clé principale du parent, obtenez ses enfants. Le problème que j'ai eu est que je dois utiliser un curseur paramétré (passer dans la clé) pour le faire.
Y a-t-il une telle chose dans SQL Server ou un tour pour imiter cela? J'ai essayé de faire ça, mais cela n'a pas fonctionné: P>
DECLARE @value VARCHAR(20); DECLARE @someKey NUMERIC(19,0); DECLARE main_curs CURSOR FOR SELECT value FROM someTable where key = @someKey; SET @someKey = 12345; OPEN main_curs FETCH NEXT FROM main_curs INTO @value; CLOSE main_curs DEALLOCATE main_curs
7 Réponses :
Vous devez définir @somekey = 12345; code> avant la déclaration du curseur tel que:
SET @someKey = 12345;
DECLARE main_curs
CURSOR FOR SELECT value FROM someTable where key = @someKey;
J'ai essayé cela et j'ai constaté que le contenu du curseur ne change pas si vous fermez le curseur, modifiez la valeur dans la variable, puis rouvrez le curseur. Il semble que la définition du curseur soit "compilée" dans la déclaration de déclaration. Je suis venu ici pour chercher un travail autour d'un peu de redécoupage du curseur.
Vous semblez avoir l'ordre des choses qui ne va pas, et vous ne faites rien dans le curseur?
DECLARE @value VARCHAR(20); DECLARE @someKey NUMERIC(19,0); SET @someKey = 12345; --this has to be set before its used in cursor declaration DECLARE main_curs CURSOR FOR SELECT value FROM someTable where key = @someKey; OPEN main_curs FETCH NEXT FROM main_curs INTO @value; -- first row is fetched WHILE @@FETCH_STATUS = 0 -- start the loop BEGIN -- do something here with @value FETCH NEXT FROM main_curs INTO @value; --fetch the next row END CLOSE main_curs DEALLOCATE main_curs
Une chose que vous pouvez essayer consiste à utiliser curseurs imbriqués . Un exemple de ceci est au bas de la page intitulée: à l'aide de curseurs imbriqués pour produire une sortie de rapport em>. P>
Si vous souhaitez itérer sur une hiérarchie récursive, utilisez des CTES, voir requêtes récursives à l'aide de Expressions de table communes . Vous pouvez déclarer votre curseur sur le CTE récursif, par exemple:
create table test ( id int not null identity(1,1) primary key, parent_id int null, data varchar (max)); go insert into test (parent_id, data) values (null, 'root'), (1, 'child 1'), (1, 'child 2') , (2, 'child of child 1'), (4, 'child of child of child 1'); go declare @root int = 2; declare crs cursor for with cte as ( select id, parent_id, data from test where id = @root union all select t.id, t.parent_id, t.data from test t join cte c on t.parent_id = c.id) select id, data from cte; open crs; declare @id int, @data varchar(max); fetch next from crs into @id, @data; while @@fetch_status = 0 begin print @data; fetch next from crs into @id, @data; end close crs; deallocate crs;
Ce dont vous avez besoin est de 2 curseurs - un pour le parent et un pour l'enfant. Make Assurez-vous que le curseur enfant est déclaré à l'intérieur de la boucle, pas à l'extérieur.La ne fonctionnera pas si vous déclarez dehors.
par exemple: P> >
DECLARE @value VARCHAR(20); DECLARE @someKey NUMERIC(19,0); DECLARE main_curs CURSOR FOR SELECT value FROM someTable where key = @someKey; SET @someKey = 12345; OPEN main_curs FETCH NEXT FROM main_curs INTO @value; while @@FETCH_STATUS = 0 BEGIN DECLARE CHILD_CURS CURSOR FOR SELECT VALUE2 FROM CHILDTABLE WHERE value=@value; open child_curs fetch next from child_curs into @x,@y close child_curs deallocate child_curs FETCH NEXT FROM main_curs INTO @value; END CLOSE main_curs DEALLOCATE main_curs
Cela fonctionne pour une valeur unique de @somekey, mais comme le dit Karl Hoaglund dans un commentaire d'une autre réponse concernant cette solution, "j'ai essayé cela et j'ai constaté que le contenu du curseur ne change pas si vous fermez le curseur, changez la valeur La variable, puis rouvrez le curseur. Il apparaît que la définition du curseur est "compilée" dans la déclaration de déclaration. Je suis venu ici pour chercher un travail autour de la redécration du curseur. " Ce qui nous donne trois à la recherche de cette réponse, y compris une ascalonienne par la mise à jour de l'OP.
@ROB - selon les informations du lien vers la documentation d'aide Microsoft sur des curseurs imbriqués Publié par John Kane, votre réponse est quelque peu inexacte. Bien qu'il soit vrai que la fermeture du curseur enfant ne change pas le contenu, le curseur d'enfant empêche le SQL pour recréer le curseur (et modifier ainsi le contenu) sur la prochaine itération de la boucle. Alors Karl est trompeur aussi bien que ce post est trompeur. Vous pouvez obtenir le curseur de l'enfant intérieur pour fonctionner comme prévu en le déroulant dans la boucle, non seulement la fermeture. Donc, cet exemple est précis.
Dans un autre endroit, une personne a suggéré d'utiliser une procédure stockée (compilée SQL plutôt qu'un script ad-hoc) mais cela ne fonctionne pas non plus. Voici une autre MWe qui montre le problème assez clairement:
/* Should print: dbNamein=master dbNameout=master dbNamein=model dbNameout=model dbNamein=msdb dbNameout=msdb */ create procedure [TestParamsWithOpenCursorStmt] as begin declare @dbNameIn [nvarchar](255) = N'tempdb', @dbNameOut [nvarchar](255), @fs [int]; declare dbNames cursor for select db.[name] from [master].[sys].[databases] db where db.[name] = @dbNameIn; while (@dbNameIn != N'msdb') begin if @dbNameIn = N'tempdb' set @dbNameIn = N'master' else if @dbNameIn = N'master' set @dbNameIn = N'model' else if @dbNameIn = N'model' set @dbNameIn = N'msdb'; open dbNames; fetch next from dbNames into @dbNameOut; set @fs = @@fetch_status; if @fs != 0 continue; raiserror (N'dbNamein=%s dbNameout=%s', 0, 0, @dbNameIn, @dbNameOut) with nowait; close dbNames; end; deallocate dbNames; end; go execute [TestParamsWithOpenCursorStmt];
Voici comment vous pouvez déclarer un curseur avec SQL dynamique, à l'aide de la fonction 'Exec ()'. Étonnamment cela fonctionne. Par exemple:
Pouvez-vous simplement interroger pour les données et ne pas utiliser de sélectionner cela est généralement plus efficace?