Platzieren eines ASSERT in einer SQL Server-Abfrage

7

Als Teil einer MERGEAbfrage, die ich ausführen möchte, möchte ich zur Laufzeit bestätigen, dass eine bestimmte Bedingung erfüllt ist. Wenn ein MERGEMatch gefunden wird, möchte ich eine bestimmte Spalte aktualisieren und die folgende Logik ausführen lassen:

  1. Wenn die Zielspalte lautet NULL, schreiben Sie den Quellwert
  2. Wenn das Ziel ist NOT NULL, behaupten Sie, dass Ziel und Quelle identisch sind

Ich erwarte, dass die beiden Werte in Fall 2 immer identisch sind, aber ich habe möglicherweise einen Fehler gemacht (habe einen Fehler). In diesem Fall möchte ich die Anweisung zum Absturz bringen und meine App den Fehler melden lassen. Dies ist eine sehr seltene Fehlerbedingung, die im Rahmen der normalen Verarbeitung nicht auftreten kann.

Also dachte ich, ich könnte eine Division durch Null missbrauchen , um einen Absturz auszulösen:

MERGE
...
WHEN MATCHED BY TARGET THEN UPDATE SET
  TargetCol = CASE
    WHEN TargetCol IS NULL THEN SourceCol
    WHEN TargetCol = SourceCol THEN SourceCol
    ELSE 0/0 END --crash!

Funktioniert das zuverlässig? Gibt es einen Grund, warum dies nicht getan werden sollte?

usr
quelle
Ich denke, RAISEERRORkönnte eine gute Wahl sein, wenn Sie innerhalb einer Abfrage behaupten möchten.
user353gre3
@ BinayaRegmi kann es nicht als Teil einer Abfrage aufrufen.
usr
Warum willst du es nicht in einem Block verwenden?
user353gre3
1
Haben Sie versucht, CHECKdie Zieltabelle OUTPUTeinzuschränken? Das sollte die Aussage in die Luft jagen.
Jon Seigel
1
@ JonSeigel Ich bezog mich auf das Dutzend bereits gefundener Zusammenführungsfehler: mssqltips.com/sqlservertip/3074/… Es gibt böse Korruptionsprobleme unter ihnen.
usr

Antworten:

3

Funktioniert das zuverlässig?

Die Antwort darauf hängt von der Stärke der Garantie ab, die Sie benötigen. In der Vergangenheit gab es Fehler in der CASEBewertungsreihenfolge, z. B. das konstante Falten eines fehlererzeugenden Ausdrucks . Es gibt keine aktuellen Fehler in SQL Server 2014, von denen ich weiß, dass sie sich auf Ihre Abfrage auswirken würden. Dies bedeutet jedoch nicht, dass sie möglicherweise in Zukunft nicht mehr auftreten.

Dies ist natürlich ein Risiko für jeden Code, aber meiner Einschätzung nach ist das Risiko höher, wenn diese Technik mit kombiniert wird MERGE. Merge hat eine komplexe Implementierung, und wie Sie wissen , gab es in der Vergangenheit viele verwandte Fehler .

Gibt es einen Grund, warum dies nicht getan werden sollte?

Persönlich würde ich versuchen, eine Division durch Null als Teil der Lösung zu vermeiden. Eine bessere Option könnte sein, zu versuchen, einen Wert zu schreiben, der eine explizite CHECK(oder eine andere) Einschränkung für die Zieltabelle verletzt . Dies würde zu einem expliziten Assert-Operator im Ausführungsplan führen, der nach dem Merge-Operator positioniert ist. Es ist möglicherweise nicht wünschenswert , eine solche Einschränkung hinzuzufügen (oder sogar möglich, wenn die Spalte alle Werte in ihrer Typdomäne enthalten darf), aber es ist eine zu berücksichtigende Sache.

Ein weiterer allgemeiner Vorschlag: Vermeiden Sie die Aktualisierung der Zielspalte, wenn die Werte übereinstimmen. Dies ist logischerweise ein No-Op, aber das wird nicht immer physisch übersetzt.

DECLARE @target AS TABLE (pk integer PRIMARY KEY, col2 integer NULL CHECK (col2 <> -1));
DECLARE @source AS TABLE (pk integer PRIMARY KEY, col2 integer NULL);

INSERT @target VALUES (1, 100), (2, NULL), (3, 300);
INSERT @source VALUES (1, 100), (2, 200), (3, 301);

MERGE @target AS T
USING @source AS S
    ON S.pk = T.pk
WHEN MATCHED 
    AND
    (
        -- No update if values match
        T.col2 IS NULL 
        OR T.col2 <> S.col2
    )
    THEN UPDATE SET col2 = 
        CASE 
            WHEN T.col2 IS NULL THEN S.col2
            ELSE -1 -- violates CHECK constraint
        END;

Plan mit Assert zusammenführen

Paul White 9
quelle
1
Das Schöne an der CHECK-Taktik ist, dass sie garantiert funktioniert. Ich werde diese Idee für die zukünftige Entwicklung wegnehmen. Im Moment bin ich mehr daran interessiert, eine extrem leichte Möglichkeit zu haben, etwas zu behaupten (vom Standpunkt der Entwicklung aus leicht). Lesen Ihrer Analyse Ich denke, der Teilungstrick ist in Ordnung für unkritische Funktionen, die keine Menschen töten, wenn sie fehlschlagen.
usr