Freitag, 17. Juni 2011

Mehr zu MERGE in T-SQL - Der Cursor Alternative!

Zu meinem Post über den MERGE Befehl des SQL Servers habe ich viel Feedback bekommen und das Interesse an mehr dazu scheint recht groß. Danke dafür!

Und tatsächlich ist der MERGE Befehl auch noch um einiges mächtiger als ich in dem Beispiel für einen einfachen ELT Ladeprozess gezeigt hatte. Und natürlich lässt sich damit mehr machen als nur einen ELT Prozess zu unterstützen.

Hier noch mal die grundlegende Syntax:

MERGE <Ziel>
USING <Quelle>
ON <Bedingung>
WHEN MATCHED THEN <Update oder Delete>
WHEN NOT MATCHED THEN <meist ein Insert>;

Nun, was geht jetzt noch? :-)

Eine interessante Möglichkeit ist, dass sowohl zwei MATCHED als auch mehrere NOT MATCHED Klauseln unterstützt werden. Für den Einsatz gibt es aber Bedingungen.

Wenn mit zwei MATCHED Klauseln gearbeitet werden soll, dann muss die erste Klausel auf jeden Fall eine erweiterte Bedingung mittels AND Klausel beinhalten. Des Weiteren kann nur einmal UPDATE und einmal DELETE genutzt werden! Also ein “wenn Du so, dann Update A und wenn Du so, dann Update B” geht nicht. Dafür muss dann die OUTPUT Klausel verwendet werden, um den Befehl mit einem weiteren zu verbinden.

Ein möglicher Anwendungsfall für zwei MATCHED ist zum Beispiel wenn ein Kennzeichen in der Quelle für das Löschen eines Datensatzes im Ziel mit übergeben wird.

Wie ist das mit der NOT MATCHED Klausel? Erst mal der Hinweis, dass T-SQL standardmäßig davon ausgeht, dass wir meinen, dass ein Satz aus der Quelle nicht im Ziel gefunden wird. Logisch, oder? Aber es gibt durchaus auch die Version WHEN NOT MATCHED BY SOURCE. Damit werden Aktionen ausgelöst, wenn ein Satz aus dem Ziel nicht “mehr” in der Quelle gefunden wurde. Für alle Mengenlehre Fans unter Euch, dass ist dann ein Right outer join. Überhaupt ist der MERGE Befehl weniger eine Mischung aus UPDATE, INSERT und DELETE als eher ein JOIN mit der Option auf Aktionen. Und WHEN NOT MATCHED BY SOURCE darf wiederum zweimal vorkommen und als Aktionen entweder ein UPDATE oder DELETE auslösen. Also ähnlich einem MATCHED.

So, und nun nicht die OUTPUT Klausel vergessen. Und nochmals der Hinweis, die gibt es auch für INSERT, DELETE und UPDATE !!!

Zwischenstand, was haben wir denn bisher:

MERGE <Ziel>
USING <Quelle>
ON <Bedingung>
WHEN MATCHED (AND …) THEN <Update oder Delete>
WHEN MATCHED (AND …) THEN <Update oder Delete>
WHEN NOT MATCHED (BY TARGET (AND)) THEN <Insert>
WHEN NOT MATCHED (BY SOURCE (AND)) THEN <Update oder Delete>
WHEN NOT MATCHED (BY SOURCE (AND)) THEN <Update oder Delete>
OUTPUT $ACTION (,…);

Des Weiteren ist wichtig zu verstehen, dass jede Zeile nur einmal evaluiert wird! Also eine ON Bedingung, welche eine 1:N Verknüpfung enthält, wird fehlschlagen, wenn diese nicht durch eine weitere Bedingung “ausgebremst” wird. Der SQL Server wirft sonst folgende Fehlermeldung:

“Die MERGE-Anweisung hat versucht, dieselbe Zeile mehr als einmal zu aktualisieren oder zu löschen. Dies passiert, wenn eine Zielzeile mehr als einer Quellzeile entspricht. Eine MERGE-Anweisung kann dieselbe Zeile der Zieltabelle nicht mehrfach aktualisieren/löschen. Optimieren Sie die ON-Klausel, um sicherzustellen, dass eine Zielzeile mindestens einer Quellzeile entspricht, oder verwenden Sie die GROUP BY-Klausel, um die Quellzeilen zu gruppieren.”

Was kann nun alles damit realisiert werden?

Gerade WHEN NOT MATCHED (BY SOURCE (AND)) THEN ermöglicht schöne Sachen. Zum Beispiel eine Historisierung von Daten, wenn diese im Quellsystem nicht mehr vorhanden sind. Also wenn Satz im Ziel vorhanden ist, aber in der Quelle nicht mehr, dann können wir diesen Löschen (wie öde) oder mittels UPDATE ein inaktiv Kennzeichen setzen. Dieses inaktiv Kennzeichen sollte dann aber auch als zusätzliche Bedingung aufgenommen werden, weil wir ja sonst immer dieses UPDATE durchführen würde, was recht suboptimal wäre.

So, und zum Abschluss noch der Hinweis an Alle, dass ich MERGE häufig als Alternative oder auch als deutliche Optimierung zum klassischen Cursor verwende! Viele Logiken, welche auf der Basis einer zeilenweise Betrachtungsweise von Tabellen basieren, lassen sich mittels MERGE bzw. auch einem zusammengesetzten Statement mit der Verwendung von OUTPUT, wesentlich effizienter gestalten!

Digg This