Ich habe eine gespeicherte Prozedur, die Benutzerdaten auf eine bestimmte Weise ändert. Ich übergebe es user_id und es macht es. Ich möchte eine Abfrage für eine Tabelle ausführen und dann für jede Benutzer-ID die gespeicherte Prozedur einmal für diese Benutzer-ID ausführen
Wie würde ich eine Abfrage dafür schreiben?
sql
sql-server
stored-procedures
MetaGuru
quelle
quelle
Antworten:
Verwenden Sie einen Cursor
ADDENDUM: [Beispiel für einen MS SQL-Cursor]
In MS SQL finden Sie hier einen Beispielartikel
Beachten Sie, dass Cursor langsamer sind als satzbasierte Operationen, aber schneller als manuelle while-Schleifen. Weitere Details in dieser SO-Frage
ADDENDUM 2: Wenn Sie mehr als nur einige Datensätze verarbeiten, ziehen Sie diese zuerst in eine temporäre Tabelle und bewegen Sie den Cursor über die temporäre Tabelle. Dies verhindert, dass SQL in Tabellensperren eskaliert, und beschleunigt den Betrieb
ADDENDUM 3: Wenn Sie natürlich inline setzen können, was Ihre gespeicherte Prozedur mit jeder Benutzer-ID tut, und das Ganze als einzelne SQL-Update-Anweisung ausführen können, wäre dies optimal
quelle
Versuchen Sie, Ihre Methode zu ändern, wenn Sie eine Schleife benötigen!
Erstellen Sie in der übergeordneten gespeicherten Prozedur eine # temp-Tabelle, die die Daten enthält, die Sie verarbeiten müssen. Wenn Sie die untergeordnete gespeicherte Prozedur aufrufen, wird die Tabelle #temp angezeigt und Sie können sie verarbeiten. Sie arbeiten hoffentlich mit dem gesamten Datensatz und ohne Cursor oder Schleife.
Dies hängt wirklich davon ab, was diese untergeordnete gespeicherte Prozedur tut. Wenn Sie UPDATE-ing sind, können Sie die Verknüpfung mit der # temp-Tabelle "aktualisieren" und die gesamte Arbeit in einer Anweisung ohne Schleife ausführen. Gleiches gilt für INSERT und DELETEs. Wenn Sie mehrere Aktualisierungen mit IFs durchführen müssen, können Sie diese
UPDATE FROM
mit der Tabelle #temp in mehrere konvertieren und CASE-Anweisungen oder WHERE-Bedingungen verwenden.Wenn Sie in einer Datenbank arbeiten und versuchen, die Einstellung zum Schleifen zu verlieren, ist dies ein echter Leistungsverlust, der zum Sperren / Blockieren führt und die Verarbeitung verlangsamt. Wenn Sie überall eine Schleife ausführen, lässt sich Ihr System nicht sehr gut skalieren und ist nur schwer zu beschleunigen, wenn Benutzer sich über langsame Aktualisierungen beschweren.
Veröffentlichen Sie den Inhalt dieser Prozedur, die Sie aufrufen möchten, in einer Schleife, und ich wette 9 von 10 Mal, Sie könnten ihn schreiben, um an einer Reihe von Zeilen zu arbeiten.
quelle
So etwas wie diese Ersetzungen werden für Ihre Tabellen und Feldnamen benötigt.
quelle
Sie können dies mit einer dynamischen Abfrage tun.
quelle
Kann dies nicht mit einer benutzerdefinierten Funktion durchgeführt werden, um zu replizieren, was auch immer Ihre gespeicherte Prozedur tut?
Dabei ist udfMyFunction eine von Ihnen erstellte Funktion, die die Benutzer-ID aufnimmt und alles tut, was Sie dazu benötigen.
Weitere Hintergrundinformationen finden Sie unter http://www.sqlteam.com/article/user-defined-functions
Ich stimme zu, dass Cursor nach Möglichkeit wirklich vermieden werden sollten. Und normalerweise ist es möglich!
(Natürlich setzt meine Antwort voraus, dass Sie nur daran interessiert sind, die Ausgabe vom SP zu erhalten, und dass Sie die tatsächlichen Daten nicht ändern. Ich finde, "ändert Benutzerdaten auf eine bestimmte Weise" ein wenig mehrdeutig gegenüber der ursprünglichen Frage. Ich dachte, ich würde dies als mögliche Lösung anbieten. Kommt ganz darauf an, was du tust!)
quelle
Verwenden Sie eine Tabellenvariable oder eine temporäre Tabelle.
Wie bereits erwähnt, ist ein Cursor das letzte Mittel. Meistens, weil es viele Ressourcen verwendet, Sperren ausgibt und möglicherweise ein Zeichen dafür ist, dass Sie nicht verstehen, wie SQL richtig verwendet wird.
Erstellen Sie eine Tabellenvariable wie diese (wenn Sie mit vielen Daten arbeiten oder wenig Speicher haben, verwenden Sie stattdessen eine temporäre Tabelle ):
Das
id
ist wichtig.Ersetzen Sie
parent
undchild
mit einigen guten Daten, z. B. relevanten Kennungen oder dem gesamten Datensatz, mit dem gearbeitet werden soll.Fügen Sie Daten in die Tabelle ein, z.
Deklarieren Sie einige Variablen:
Erstellen Sie abschließend eine while-Schleife über die Daten in der Tabelle:
Die erste Auswahl ruft Daten aus der temporären Tabelle ab. Die zweite Auswahl aktualisiert die @id.
MIN
Gibt null zurück, wenn keine Zeilen ausgewählt wurden.Ein alternativer Ansatz besteht darin, eine Schleife zu erstellen, während die Tabelle Zeilen enthält,
SELECT TOP 1
und die ausgewählte Zeile aus der temporären Tabelle zu entfernen:quelle
Ich mag die dynamische Abfrage von Dave Rincon, da sie keine Cursor verwendet und klein und einfach ist. Vielen Dank, Dave, für das Teilen.
Aber für meine Anforderungen an Azure SQL und mit einem "eindeutigen" in der Abfrage musste ich den Code wie folgt ändern:
Ich hoffe das hilft jemandem ...
quelle