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).

War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top