SQL Server OUTPUT: Änderungen zuverlässig erfassen
Erfassen Sie Schlüssel und Vorher-Nachher-Werte mit OUTPUT und berücksichtigen Sie Reihenfolge, Trigger, Fehler und Wiederholungen.
Nach einer Aktualisierung dieselben Zeilen erneut abzufragen beantwortet eine andere Frage: Welche Zeilen wurden geändert, und was enthalten passende Zeilen jetzt? Unter konkurrierender Last können diese Antworten auseinanderliegen. OUTPUT bindet das Ergebnis direkt an die ändernde Anweisung und eignet sich deshalb für erzeugte Schlüssel, Vorher-Nachher-Werte und präzise Anwendungsantworten.
Eine eindeutige Zuordnung erfassen
Das Beispiel nutzt temporäre Tabellen und ändert zwei Bestandszeilen. Es erfasst Schlüssel, alte Menge und neue Menge aus demselben UPDATE. Das abschließende ORDER BY definiert die Darstellung, ohne sich auf die physische Änderungsreihenfolge zu verlassen.
IF @@TRANCOUNT <> 0
THROW 50000, 'This example owns its transaction.', 1;
SET XACT_ABORT ON;
CREATE TABLE #Stock (ItemId int PRIMARY KEY, Qty int NOT NULL);
INSERT #Stock VALUES (1, 12), (2, 20);
CREATE TABLE #Changed (ItemId int, OldQty int, NewQty int);
BEGIN TRY
BEGIN TRAN;
UPDATE #Stock
SET Qty = Qty - 2
OUTPUT inserted.ItemId, deleted.Qty, inserted.Qty
INTO #Changed(ItemId, OldQty, NewQty)
WHERE ItemId IN (1, 2) AND Qty >= 2;
COMMIT;
SELECT ItemId, OldQty, NewQty FROM #Changed ORDER BY ItemId;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK;
THROW;
END CATCH;
Behalten Sie den Schlüssel im Ergebnis. Liefert die Anwendung nur Mengen zurück, muss der Client deren Zuordnung erraten. Bei Mehrzeilen-Inserts sollte ein eindeutiger Korrelationswert des Clients gespeichert und gemeinsam mit der erzeugten Identity ausgegeben werden. Die erste zurückgegebene Identity gehört nicht garantiert zur ersten Eingabezeile.
Erfassen Sie nur benötigte Spalten. OUTPUT inserted.* koppelt eine Schnittstelle an die Tabellenstruktur und kann große Werte unnötig kopieren. Explizite Spaltenlisten machen Typänderungen sichtbar und reduzieren die unbeabsichtigte Weitergabe interner Felder.
Ausgabe und erfolgreichen Commit unterscheiden
Die Transaktionsgrenze bleibt entscheidend. OUTPUT bestätigt keinen endgültigen fachlichen Commit. Eine spätere Anweisung kann scheitern, die Transaktion kann zurückrollen oder die Verbindung während der Commit-Bestätigung verloren gehen. Der Client muss das vollständige Ergebnis einschließlich Fehlern auswerten, bevor er die Operation als erfolgreich behandelt.
Das Beispiel schreibt die Ausgabe in eine temporäre Tabelle, bestätigt und liefert erst danach die Zeilen zurück. Bei Fehlern rollt CATCH zurück und wirft die Ausnahme erneut, statt Erfolg auszugeben. Die Prüfung verbietet eine äußere Transaktion: Sonst könnte die Routine Erfolg melden, obwohl erst der Aufrufer über den endgültigen Commit entscheidet.
Damit ist die Reihenfolge der lokalen Antwort geregelt, nicht der Verlust dieser Antwort. War der Commit erfolgreich und erreicht die Antwort den Client nicht, benötigt eine Wiederholung eine dauerhafte Vorgangskennung. Die temporäre Tabelle verschwindet mit der Sitzung und kann eine spätere Anfrage nicht beantworten. Speichern Sie Zuordnung und Ergebnis dauerhaft, wenn die Schreibschnittstelle wiederholungssicher sein muss.
Trigger und Audit bewusst behandeln
Die von OUTPUT gelieferten inserted-Werte stammen aus der Änderung vor der Ausführung von AFTER-Triggern. Normalisiert ein Trigger danach einen Wert, kann die Ausgabe vom endgültigen Tabelleninhalt abweichen. Legen Sie fest, welches Ergebnis der Client benötigt. Für endgültige Werte können zunächst Schlüssel erfasst und anschließend innerhalb eines passenden Transaktionskonzepts erneut gelesen werden.
Eine direkte OUTPUT-Ausgabe besitzt außerdem Einschränkungen bei aktivierten Triggern für die betreffende Aktion. OUTPUT INTO ist dann häufig die passende Form, hat aber eigene Anforderungen an die Zieltabelle. Prüfen Sie Trigger und Constraints im echten Schema, nicht nur eine leere Testtabelle.
Eine an den Client gesendete Ausgabe ist kein dauerhaftes Audit. Eine Audit-Tabelle in derselben Transaktion erfasst bestätigte Änderungen, verliert ihren Eintrag aber beim Rollback ebenfalls. Fehlgeschlagene Versuche benötigen ein anderes Konzept. Unterscheiden Sie ausdrücklich zwischen erfolgreichen Zustandswechseln und versuchten Operationen.
Messen Sie schließlich den Aufwand großer Änderungen. Millionen Vorher-Nachher-Zeilen können Speicher, Journal und Netzwerk erheblich belasten. Eine schmale Antwort aus Schlüssel und Status reicht häufig aus. Testen Sie Erfolg, erzwungene Fehler, triggerveränderte Werte und die Zuordnung mehrerer Eingaben. Prüfen Sie dabei auch, dass der Client bei einem Fehler keine bereits gelesenen Ausgabezeilen als bestätigte Änderungen weiterverarbeitet. Erst diese Kombination macht den Schnittstellenvertrag nachvollziehbar.
Technische Referenzen: Microsoft Learn: OUTPUT · Microsoft Learn: TRY CATCH.