Update-No-op in SQL Merge-Anweisung
-
24-10-2019 - |
Frage
Ich habe eine Tabelle mit einigen anhaltenden Daten. Wenn ich es nun abfragt, habe ich auch einen ziemlich komplexen CTE, der die für das Ergebnis erforderlichen Werte berechnet, und ich muss fehlende Zeilen in die persistente Tabelle einfügen. Am Ende möchte ich das Ergebnis auswählen, das aus allen vom CTE identifizierten Zeilen besteht, jedoch mit den Daten aus der Tabelle, wenn sie sich bereits in der Tabelle befanden, und ich brauche die Informationen, ob eine Zeile gerade eingefügt wurde oder nicht.
Vereinfacht dies funktioniert so (der folgende Code wird als normale Abfrage ausgeführt, wenn Sie es versuchen möchten):
-- Set-up of test data, this would be the persisted table
DECLARE @target TABLE (id int NOT NULL PRIMARY KEY) ;
INSERT INTO @target (id) SELECT v.id FROM (VALUES (1), (2)) v(id);
-- START OF THE CODE IN QUESTION
-- The result table variable (will be several columns in the end)
DECLARE @result TABLE (id int NOT NULL, new bit NOT NULL) ;
WITH Source AS (
-- Imagine a fairly expensive, recursive CTE here
SELECT * FROM (VALUES (1), (3)) AS Source (id)
)
MERGE INTO @target AS Target
USING Source
ON Target.id = Source.id
-- Perform a no-op on the match to get the output record
WHEN MATCHED THEN
UPDATE SET Target.id=Target.id
WHEN NOT MATCHED BY TARGET THEN
INSERT (id) VALUES (SOURCE.id)
-- select the data to be returned - will be more columns
OUTPUT source.id, CASE WHEN $action='INSERT' THEN CONVERT(bit, 1) ELSE CONVERT(bit, 0) END
INTO @result ;
-- Select the result
SELECT * FROM @result;
Ich mag das nicht WHEN MATCHED THEN UPDATE
Teil, ich würde das redundante Update lieber fern lassen, aber dann bekomme ich nicht die Ergebniszeile in der OUTPUT
Klausel.
Ist dies der effizienteste Weg, um diese Art von Daten zu erledigen und zurückzugeben?
Oder würde es eine effizientere Lösung ohne geben MERGE
, Zum Beispiel durch Vorbereitung des Ergebnisses mit a SELECT
und dann eine durchführen INSERT
der Reihen, die sind new=0
? Ich habe Schwierigkeiten bei der Interpretation des Abfrageplan SELECT
gefolgt von INSERT
Variante. Und ich frage mich, ob SQL Server (2008 R2 mit CU1) tatsächlich klug genug ist, um zu sehen, dass die UPDATE
ist ein No-op (zB kein Schreiben erforderlich).
Lösung
Sie können eine Dummy -Variable deklarieren und ihren Wert in der WO -übereinstimmenden Klausel festlegen.
DECLARE @dummy int;
...
MERGE
...
WHEN MATCHED THEN
UPDATE SET @dummy = 0
...
Ich glaube, es sollte günstiger sein als das tatsächliche Tischaktualisierung.