Ich habe drei gespeicherte Prozeduren Sp1
, Sp2
und Sp3
.
Das erste ( Sp1
) führt das zweite ( Sp2
) aus und speichert zurückgegebene Daten in @tempTB1
und das zweite führt das dritte ( Sp3
) aus und speichert Daten in @tempTB2
.
Wenn ich das ausführe Sp2
, funktioniert es und es gibt mir alle meine Daten von dem zurück Sp3
, aber das Problem liegt darin Sp1
, dass bei der Ausführung der folgende Fehler angezeigt wird:
Die Anweisung INSERT EXEC kann nicht verschachtelt werden
Ich habe versucht, den Ort zu ändern, execute Sp2
und es wird mir ein weiterer Fehler angezeigt:
Die ROLLBACK-Anweisung kann nicht in einer INSERT-EXEC-Anweisung verwendet werden.
sp_help_jobactivity
Dies ist die einzige "einfache" Möglichkeit, dies in SQL Server ohne eine riesige, verschlungene, erstellte Funktion oder einen ausgeführten SQL-String-Aufruf zu tun. Beides sind schreckliche Lösungen:
BEISPIEL:
Hinweis : Sie MÜSSEN 'set fmtonly off' verwenden, und Sie können diesem weder innerhalb des openrowset-Aufrufs dynamisches SQL hinzufügen, weder für die Zeichenfolge, die Ihre Parameter für gespeicherte Prozeduren enthält, noch für den Tabellennamen. Aus diesem Grund müssen Sie eine temporäre Tabelle anstelle von Tabellenvariablen verwenden, was besser gewesen wäre, da in den meisten Fällen eine temporäre Tabelle ausgeführt wird.
quelle
OK, ermutigt von Jimhark hier ist ein Beispiel für den alten Single-Hash-Table-Ansatz: -
quelle
Meine Problemumgehung bestand immer darin, das Prinzip zu verwenden, dass einzelne Hash-temporäre Tabellen für alle aufgerufenen Prozesse gelten. Ich habe also einen Optionsschalter in den Proc-Parametern (standardmäßig ausgeschaltet). Wenn dies aktiviert ist, fügt der aufgerufene Prozess die Ergebnisse in die temporäre Tabelle ein, die im aufrufenden Prozess erstellt wurde. Ich denke, in der Vergangenheit bin ich noch einen Schritt weiter gegangen und habe Code in den aufgerufenen Prozess eingefügt, um zu überprüfen, ob die einzelne Hash-Tabelle im Gültigkeitsbereich vorhanden ist. Wenn dies der Fall ist, wird der Code eingefügt, andernfalls wird die Ergebnismenge zurückgegeben. Scheint gut zu funktionieren - die beste Möglichkeit, große Datenmengen zwischen Prozessen zu übertragen.
quelle
Dieser Trick funktioniert bei mir.
Dieses Problem tritt auf dem Remoteserver nicht auf, da auf dem Remoteserver der letzte Einfügebefehl auf die Ausführung des Ergebnisses des vorherigen Befehls wartet. Dies ist auf demselben Server nicht der Fall.
Profitieren Sie von dieser Situation für eine Problemumgehung.
Wenn Sie die richtige Berechtigung zum Erstellen eines Verbindungsservers haben, tun Sie dies. Erstellen Sie denselben Server wie den Verbindungsserver.
Jetzt lautet Ihr SQL-Befehl im SP1
Glauben Sie mir, es funktioniert auch, wenn Sie eine dynamische Einfügung in SP2 haben
quelle
Ich fand eine Lösung, um eines der Produkte in eine Tabellenwertfunktion umzuwandeln. Mir ist klar, dass dies nicht immer möglich ist, und es gibt seine eigenen Einschränkungen. Es ist mir jedoch immer gelungen, mindestens eines der Verfahren als guten Kandidaten dafür zu finden. Ich mag diese Lösung, weil sie keine "Hacks" in die Lösung einführt.
quelle
Dieses Problem trat auf, als ich versuchte, die Ergebnisse eines gespeicherten Prozesses in eine temporäre Tabelle zu importieren, und dieser gespeicherte Prozess wurde als Teil seiner eigenen Operation in eine temporäre Tabelle eingefügt. Das Problem ist, dass SQL Server nicht zulässt, dass derselbe Prozess gleichzeitig in zwei verschiedene temporäre Tabellen schreibt.
Die akzeptierte OPENROWSET-Antwort funktioniert einwandfrei, aber ich musste vermeiden, Dynamic SQL oder einen externen OLE-Anbieter in meinem Prozess zu verwenden, also bin ich einen anderen Weg gegangen.
Eine einfache Problemumgehung bestand darin, die temporäre Tabelle in meiner gespeicherten Prozedur in eine Tabellenvariable zu ändern. Es funktioniert genauso wie bei einer temporären Tabelle, steht jedoch nicht mehr in Konflikt mit meiner anderen temporären Tabelleneinfügung.
Nur um den Kommentar abzuwenden, ich weiß, dass einige von Ihnen im Begriff sind zu schreiben und mich vor Tabellenvariablen als Leistungskiller warnen ... Ich kann Ihnen nur sagen, dass es sich im Jahr 2020 auszahlt, keine Angst vor Tabellenvariablen zu haben. Wenn dies 2008 war und meine Datenbank auf einem Server mit 16 GB RAM und 5400 U / min-Festplatten gehostet wurde, stimme ich Ihnen möglicherweise zu. Aber es ist 2020 und ich habe ein SSD-Array als primären Speicher und Hunderte von GB RAM. Ich könnte die Datenbank meines gesamten Unternehmens in eine Tabellenvariable laden und trotzdem genügend RAM zur Verfügung haben.
Tabellenvariablen sind wieder im Menü!
quelle
Ich hatte das gleiche Problem und die gleiche Besorgnis über doppelten Code in zwei oder mehr Sprocs. Am Ende habe ich ein zusätzliches Attribut für "Modus" hinzugefügt. Dies ermöglichte es, dass gemeinsamer Code innerhalb eines Sprocs und des modengesteuerten Flusses und der Ergebnismenge des Sprocs vorhanden war.
quelle
Was ist mit dem Speichern der Ausgabe in der statischen Tabelle? Mögen
Es ist nicht ideal, aber es ist so einfach und Sie müssen nicht alles neu schreiben.
UPDATE : Die vorherige Lösung funktioniert nicht gut mit parallelen Abfragen (asynchroner und Mehrbenutzerzugriff), daher verwende ich jetzt temporäre Tabellen
verschachtelter
spGetData
Inhalt der gespeicherten Prozedurquelle
Deklarieren Sie eine Ausgabecurservariable zum inneren sp:
Deklarieren Sie dann einen Cursor c auf die Auswahl, die Sie zurückgeben möchten. Öffnen Sie dann den Cursor. Stellen Sie dann die Referenz ein:
NICHT schließen oder neu zuweisen.
Rufen Sie nun das innere sp vom äußeren auf und geben Sie einen Cursorparameter wie folgt ein:
Sobald der innere sp ausgeführt wird, können Sie ihn
@cOUT
abrufen. Schleife und dann schließen und freigeben.quelle
Wenn Sie andere zugehörige Technologien wie C # verwenden können, empfehle ich die Verwendung des integrierten SQL-Befehls mit dem Transaktionsparameter.
Ich habe eine einfache Konsolen-App erstellt, die diese Fähigkeit demonstriert. Sie finden sie hier: https://github.com/hecked12/SQL-Transaction-Using-C-Sharp
Kurz gesagt, mit C # können Sie diese Einschränkung überwinden, indem Sie die Ausgabe jeder gespeicherten Prozedur überprüfen und diese Ausgabe verwenden können, wie Sie möchten. Sie können sie beispielsweise einer anderen gespeicherten Prozedur zuführen. Wenn die Ausgabe in Ordnung ist, können Sie die Transaktion festschreiben. Andernfalls können Sie die Änderungen mithilfe des Rollbacks zurücksetzen.
quelle
Unter SQL Server 2008 R2 hatte ich eine Nichtübereinstimmung in Tabellenspalten, die den Rollback-Fehler verursachte. Es verschwand, als ich meine von der insert-exec-Anweisung aufgefüllte sqlcmd-Tabellenvariable so korrigierte, dass sie mit der vom gespeicherten Prozess zurückgegebenen übereinstimmt. Es fehlte org_code. In einer Windows-Cmd-Datei wird das Ergebnis der gespeicherten Prozedur geladen und ausgewählt.
quelle