Wie kann man eine gespeicherte Prozedur für jede Zeile in einer Tabelle aufrufen, wobei die Spalten einer Zeile Eingabeparameter für sp sind, ohne einen Cursor zu verwenden?
sql
sql-server
stored-procedures
cursor
Johannes Rudolph
quelle
quelle
Antworten:
Im Allgemeinen suche ich immer nach einem satzbasierten Ansatz (manchmal auf Kosten der Änderung des Schemas).
Dieses Snippet hat jedoch seinen Platz.
quelle
Sie könnten Folgendes tun: Ordnen Sie Ihre Tabelle nach z. B. CustomerID (mithilfe der AdventureWorks-
Sales.Customer
Beispieltabelle) und durchlaufen Sie diese Kunden mithilfe einer WHILE-Schleife:Das sollte mit jeder Tabelle funktionieren, solange Sie eine Art
ORDER BY
Spalte definieren können.quelle
Ok, ich würde niemals solchen Code in die Produktion einbauen, aber er erfüllt Ihre Anforderungen.
quelle
Marc's Antwort ist gut (ich würde es kommentieren, wenn ich herausfinden könnte, wie es geht!)
Ich dachte nur, ich würde darauf hinweisen, dass es besser sein könnte, die Schleife so zu ändern, dass die
SELECT
nur einmal existiert (in einem realen Fall, in dem ich musste Wenn Sie dies tun,SELECT
war das ziemlich komplex und das zweimalige Schreiben war ein riskantes Wartungsproblem.quelle
Wenn Sie die gespeicherte Prozedur in eine Funktion verwandeln können, die eine Tabelle zurückgibt, können Sie cross-apply verwenden.
Angenommen, Sie haben eine Kundentabelle und möchten die Summe ihrer Bestellungen berechnen. Sie würden eine Funktion erstellen, die eine Kunden-ID verwendet und die Summe zurückgibt.
Und Sie könnten dies tun:
Wo die Funktion aussehen würde:
Offensichtlich könnte das obige Beispiel ohne eine benutzerdefinierte Funktion in einer einzelnen Abfrage durchgeführt werden.
Der Nachteil ist, dass die Funktionen sehr eingeschränkt sind - viele der Funktionen einer gespeicherten Prozedur sind in einer benutzerdefinierten Funktion nicht verfügbar, und die Konvertierung einer gespeicherten Prozedur in eine Funktion funktioniert nicht immer.
quelle
Ich würde die akzeptierte Antwort verwenden, aber eine andere Möglichkeit besteht darin, eine Tabellenvariable zu verwenden, um einen nummerierten Satz von Werten (in diesem Fall nur das ID-Feld einer Tabelle) zu speichern und diese nach Zeilennummer mit einem JOIN zur Tabelle zu durchlaufen Rufen Sie alles ab, was Sie für die Aktion innerhalb der Schleife benötigen.
quelle
Ab SQL Server 2005 können Sie dies mit CROSS APPLY und einer Tabellenwertfunktion tun .
Aus Gründen der Klarheit beziehe ich mich auf die Fälle, in denen die gespeicherte Prozedur in eine Tabellenwertfunktion konvertiert werden kann.
quelle
Dies ist eine Variation der obigen n3rds-Lösung. Es ist keine Sortierung mit ORDER BY erforderlich, da MIN () verwendet wird.
Denken Sie daran, dass die Kunden-ID (oder eine andere numerische Spalte, die Sie für den Fortschritt verwenden) eine eindeutige Einschränkung haben muss. Um es so schnell wie möglich zu machen, muss außerdem die Kunden-ID indiziert werden.
Ich verwende diesen Ansatz bei einigen Varchars, die ich überprüfen muss, indem ich sie zuerst in eine temporäre Tabelle lege, um ihnen eine ID zu geben.
quelle
Wenn Sie nicht wissen, was Sie mit einem Cursor verwenden sollen, müssen Sie dies meiner Meinung nach extern tun (die Tabelle abrufen und dann für jede Anweisung ausführen und jedes Mal den sp aufrufen). Dies entspricht der Verwendung eines Cursors, jedoch nur außerhalb SQL. Warum benutzt du keinen Cursor?
quelle
Dies ist eine Variation der bereits bereitgestellten Antworten, sollte jedoch eine bessere Leistung erbringen, da ORDER BY, COUNT oder MIN / MAX nicht erforderlich sind. Der einzige Nachteil bei diesem Ansatz besteht darin, dass Sie eine temporäre Tabelle erstellen müssen, um alle IDs zu speichern (die Annahme ist, dass Sie Lücken in Ihrer Liste der Kunden-IDs haben).
Trotzdem stimme ich @Mark Powell zu, obwohl ein satzbasierter Ansatz im Allgemeinen immer noch besser sein sollte.
quelle
Normalerweise mache ich das so, wenn es einige Zeilen sind:
(Bei größeren Datensätzen würde ich jedoch eine der oben genannten Lösungen verwenden).
quelle
DELIMITER //
quelle
Eine bessere Lösung dafür ist zu
Auf diese Weise erhalten Sie eine saubere, tabellenformatierte Ausgabe. Wenn Sie SP für jede Zeile ausführen, erhalten Sie für jede hässliche Iteration ein separates Abfrageergebnis.
quelle
Falls die Reihenfolge wichtig ist
quelle
Ich hatte einen Produktionscode, der nur 20 Mitarbeiter gleichzeitig verarbeiten konnte. Nachfolgend finden Sie den Rahmen für den Code. Ich habe gerade den Produktionscode kopiert und das unten stehende Material entfernt.
quelle
Ich mache gerne etwas Ähnliches (obwohl es der Verwendung eines Cursors immer noch sehr ähnlich ist)
[Code]
[/Code]
Beachten Sie, dass Sie weder die Identität noch die Spalte isIterated in Ihrer temporären / variablen Tabelle benötigen. Ich bevorzuge es einfach so, damit ich den obersten Datensatz nicht aus der Sammlung löschen muss, während ich durch die Schleife iteriere.
quelle