Je cherche un moyen d'appeler une procédure stockée pour chaque enregistrement d'une instruction select. Une telle chose ci-dessus ne fonctionne pas bien sûr, mais y a-t-il un moyen de faire quelque chose comme ça?SQL - Procédure stockée d'appel pour chaque enregistrement
Répondre
Vous devez utiliser un curseur pour cela.
DECLARE @oneid int -- or the appropriate type
DECLARE the_cursor CURSOR FAST_FORWARD
FOR SELECT spro.Id
FROM SomeTable as spro
INNER JOIN [Address] addr ON addr.Id = spro.Id
INNER JOIN City cty ON cty.CityId = addr.CityId
WHERE cty.CityId = @CityId
OPEN the_cursor
FETCH NEXT FROM the_cursor INTO @oneid
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC UpdateComputedFullText @oneid
FETCH NEXT FROM the_cursor INTO @oneid
END
CLOSE the_cursor
DEALLOCATE the_cursor
A l'OP, notez que les curseurs sont maléfiques et vous devriez les éviter à tout prix, mais je leur donne encore +1 car leur utilisation peut être justifiée dans certains cas comme celui-ci. Espérons que ceci est une chose ponctuelle et que vous n'allez pas placer ce curseur dans un autre proc :) –
(-1) Les curseurs sont HORRIBLE surtout depuis les nouvelles versions de SQL Server. Cette syntaxe basée sur Set et Set est beaucoup plus élégante et succincte - sans parler des ordres sur des ordres de grandeur plus rapides. –
Les curseurs ne sont pas mauvais - c'est simpliste. Si possible, réécrivez des solutions itératives (curseurs ou en boucle) en utilisant une solution basée sur un ensemble. Sans informations supplémentaires, vous devez itérer dans ce cas et un curseur est bon. – Precipitous
Vous aurez besoin d'utiliser un curseur: SQL Server Cursor Examples
DECLARE @id int
DECLARE cursor_sample CURSOR FOR
SELECT spro.Id
FROM SomeTable as spro
INNER JOIN [Address] addr ON addr.Id = spro.Id
INNER JOIN City cty ON cty.CityId = addr.CityId
WHERE cty.CityId = @CityId
OPEN cursor_sample
FETCH NEXT FROM cursor_sample INTO @id
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC UpdateComputedFullText @id
FETCH NEXT FROM cursor_sample INTO @id
END
CLOSE cursor_sample
DEALLOCATE cursor_sample
Mettez le Ids dans une variable de table temporaire, puis itérer throught chaque ligne: (Vous n'êtes pas obligé d'utiliser un curseur qui sera beaucoup plus lent)
Declare @Keys Table (key integer Primary Key Not Null)
Insert @Keys(key)
SELECT spro.Id
FROM SomeTable as spro
JOIN [Address] addr ON addr.Id = spro.Id
JOIN City cty ON cty.CityId = addr.CityId
WHERE cty.CityId = @CityId
-- -------------------------------------------
Declare @Key Integer
While Exists (Select * From @Keys)
Begin
Select @Key = Max(Key) From @Keys
EXEC UpdateComputedFullText @Key
Delete @Keys Where Key = @Key
End
EDIT Supprimer ne tarde pas lorsqu'il est utilisé avec un prédicat de filtre dirigé contre un index unique très étroit, comme c'est le cas. Mais il peut facilement être évité, juste en faisant boucle comme suit:
Declare @Key Integer = 0
While Exists (Select * From @Keys
Where key > @Key)
Begin
Select @Key = Min(Key) From @Keys
Where key > @Key
EXEC UpdateComputedFullText @Key
-- Delete @Keys Where Key = @Key No Longer necessary
End
Ceci est une approche intéressante. :) – treaschf
ok, les curseurs sont lents, mais est-ce plus rapide? –
J'aime ça. Les curseurs sont mauvais. :) –
Les deux réponses ci-dessus RE curseurs sont corrects. Cependant, en fonction de la complexité du code qui s'exécute à l'intérieur du curseur, il est préférable de laisser tomber ceci dans la langue de votre choix et d'effectuer vos calculs dans le code avant de déposer les résultats dans une base de données.
Je me suis retrouvé à revenir en arrière et à passer en revue un grand nombre d'opérations de curseur, et dans la plupart des cas, je les ai fait passer au code pour des raisons de performances.
Essayez celui-ci sans curseur
DECLARE @id int
SELECT top 1 @id = spro.Id
FROM SomeTable as spro
INNER JOIN [Address] addr ON addr.Id = spro.Id
INNER JOIN City cty ON cty.CityId = addr.CityId
WHERE cty.CityId = @CityId
ORDER BY spro.id
WHILE @@ROWCOUNT > 0
BEGIN
EXEC UpdateComputedFullText @id
SELECT top 1 @id = spro.Id
FROM SomeTable as spro
INNER JOIN [Address] addr ON addr.Id = spro.Id
INNER JOIN City cty ON cty.CityId = addr.CityId
WHERE cty.CityId = @CityId
and spro.id > @id
ORDER BY spro.id
END
Ceci est un dogme sans raison - lettre de la loi au lieu de l'esprit de la loi. La raison principale pour éviter les curseurs est qu'il existe presque toujours une solution basée sur un ensemble plus efficace. Cela évite les curseurs mais ne fournit pas de solution basée sur un ensemble. Bien sûr, nous ne savons pas qu'il existe une solution basée sur un ensemble à ce problème. – Precipitous
(+1) J'ai été informé par mes collègues qui font du traitement de données à l'échelle du téraoctet en SQL qu'un 'WHILE' pour l'itération fonctionne assez bien - surtout quand il n'y a pas de choix - de nos jours cependant TVF + CROSS APPLY = king (voir ma réponse). –
-vous vraiment besoin de faire un traitement ligne par ligne lorsque le traitement est mis disponible?
Vous pouvez placer les résultats du SELECT dans une table temporaire, puis appeler un proc pour effectuer un SQL en masse par rapport au contenu de la table temporaire. La table temporaire sera disponible pour le processus appelé en fonction des règles de portée T-SQL.
Surpris personne ne vous a donné une réponse à jour. Les curseurs sont mauvais. Qu'est-ce que vous voulez est de déplacer la logique du SP dans un table-valued-function(TVF) and then use CROSS APPLY
Voici une requête que j'ai écrit hier (ne pas s'attarder sur les détails, il suffit de regarder le CROSS APPLY
). Le CROSS APPLY
crée une union de tables. Chaque élément de cette union est généré à partir du TVF qui est paramétré sur les entrées de ligne de l'instruction select.
SELECT supt.hostname,supt.scriptname, COUNT(*)
FROM Event_Pagehit eph
INNER JOIN Symboltable_urlpair supf
ON eph.fromPagePair=supf.id
INNER JOIN Symboltable_urlpair supt
ON supt.id=eph.toPagePair
CROSS APPLY dbo.TDFCompanyFormationsUrlClassification(supf.hostname,supf.scriptname) as x
CROSS APPLY dbo.TDFCompanyFormationsUrlClassification(supt.hostname,supt.scriptname) as y
WHERE x.isCompanyFormations=1
AND y.isCompanyFormations=0
GROUP BY supt.hostname,supt.scriptname
ORDER BY COUNT(*) desc
Je peux utiliser x
et y
comme si elles étaient tirés dans les tables des clauses FROM
ou JOIN
. Si je devais écrire cette requête sans TVF, cela couvrirait quelques centaines de lignes.
Note:
Si vous ne pouvez pas réécrire la SP: vous devriez être en mesure d'insérer le résultat d'une procédure stockée dans la table de résultats à partir d'une fonction table. Je n'ai jamais fait cela, et parfois les constructeurs de serveurs SQL différents ont des réserves - Donc, à moins que quelqu'un dise le contraire, je suppose que c'est le cas.
(+1) Je suis toujours ouvert aux nouvelles solutions, surtout si elles sont définies base. –
Question sur ce produit? Est-ce que le 'CROSS APPLY' se produit avant ou après la clause where? Je sais où le mettre dans la déclaration, mais est-ce qu'il * exécute * en utilisant les éléments pré-filtrés ou post-filtrés du 'WHERE' en dessous? – SnareChops
Comment cela s'applique-t-il si vous utilisez un proc qui ne retourne pas un ensemble de résultats? Supposons que vous fournissiez une liste d'identifiants utilisateur dans un proc appelé deleteUser (comme asp.net dans le cadre d'adhésion), vous êtes presque bloqué avec un curseur ou une instruction while, non? – Andrew
La solution de curseur standard est le mal sur le mal. Deux instructions FETCH NEXT identiques ne sont qu'un cauchemar de maintenance.
mieux est
...declare cursor etc.
While 1=1
Fetch ...
if @@FETCH_STATUS <> 0 BREAK
...
End -- While
..Close cursor etc.
Un mal parfois justifié. Essayez simplement de concevoir une approche basée sur un ensemble pour l'envoi d'e-mails de notification à l'aide de sp_send_dbmail ou d'une autre procédure stockée.
- 1. Exécuter la procédure stockée pour chaque enregistrement dans le tableau
- 2. Procédure stockée SQL Question
- 3. Utilisation d'une procédure stockée et NHibernate pour insérer un enregistrement
- 4. SQL Server procédure stockée exécutée chaque jour en même temps
- 5. procédure stockée C# SQL
- 6. serveur Sql procédure stockée
- 7. Procédure stockée SQL Server
- 8. Affichage oracle pour chaque procédure stockée le temps d'exécution
- 9. Alerte SQL pour une procédure stockée?
- 10. Procédure stockée SQL Rejoindre la question
- 11. Travail SQL et procédure stockée
- 12. signifie SQL Server procédure stockée
- 13. lastest enregistrement pour chaque clé - SQL
- 14. sql procédure stockée paramètre problème
- 15. MS SQL procédure stockée problème
- 16. LINQ to SQL (procédure stockée)
- 17. SQL procédure stockée: Heures d'ouverture
- 18. Procédure stockée SQL Server 2008
- 19. Dynamic SQL Server procédure stockée
- 20. procédure stockée t-sql créer des scripts
- 21. SQL boucles procédure stockée question du serveur
- 22. Créer une classe personnalisée pour chaque procédure stockée en utilisant linq to SQL?
- 23. procédure stockée partagée
- 24. Procédure stockée exécutant une autre procédure stockée
- 25. T-SQL Procédure stockée avec plusieurs sélections
- 26. Procédure stockée Sql Like Variable d'opérateur
- 27. SQL Tout en ralentissant la procédure stockée
- 28. Asp.net MVC avec SQL Server procédure stockée
- 29. SHA256 dans une procédure stockée T-SQL
- 30. '1 = 1' dans SQL procédure stockée
Tout le monde vous supplie d'éviter l'itération (curseurs ou while). Que fait le sproc, donc nous pouvons définir une solution basée sur un ensemble? – Precipitous
Je n'ai pas supprimé mon approche basée sur les ensembles - j'étais pressé auparavant et je ne voulais pas continuer sans une 'note' à la fin. –