Blog
Tuesday, 06. September 2022

T-SQL - Der MERGE Befehl

Anna
Teamleitung Website & Content

In einem üblichen ETL Zyklus kommt es vor, dass eine Synchronisation zwischen der Ursprungs-und Zieltabelle stattfindet. Denn bei der Operation ist es wichtig, dass beide Tabellen auf dem aktuellen Stand sind. Ohne den MERGE Befehl wäre es zwingend notwendig drei separate Befehle auszuführen: INSERT, UPDATE und DELETE. Nicht nur ist das Ausführen aufwendig, es besteht ebenfalls die Gefahr, dass einem bei diesem Vorgehen ein Fehler unterläuft und Daten potenziell verloren gehen.

Die Lösung für dieses Problem stellt der MERGE Befehl dar. Dieser ist vergleichbar mit dem UPSERT Befehl von Oracle. Analog führen beide Befehle eine Operation mit den drei DML Befehlen aus. Hierbei ist es lediglich notwendig, seine Parameter und Bedingungen anzugeben.

MERGE <target_table> [AS TARGET]
USING <table_source> [AS SOURCE]
ON <search_condition>
[WHEN MATCHED 
   THEN <merge_matched> ]
[WHEN NOT MATCHED [BY TARGET]
   THEN <merge_not_matched> ]
[WHEN NOT MATCHED BY SOURCE
   THEN <merge_matched> ];

Wie eben erwähnt führt der MERGE Befehl INSERT, UPDATE und DELETE zusammen aus. Notwendig ist es, dass Sie die Ursprungs-und Zieltabelle angeben. Außerdem, die Bedingungen, wie z.B. “Wenn es die Daten nur in einer Tabelle gibt, dann aktualisiere (UPDATE) diese Tabelle”.

Legen Sie los!

  1. Identifizieren Sie den Namen der Zieltabelle.
  2. Identifizieren Sie den Namen der Ursprungstabelle.
  3. Verwenden Sie nun eine passende ON Bedingung, die die einzelnen Reihen miteinander übereinstimmen lässt.
  4. Bestimmen Sie nun die Bedingungen, die zwischen Ziel- und Ursprungstabelle geprüft werden.
  5. Konfigurieren Sie daraufhin, was passieren soll, wenn die Bedingungen in Schritt 4 zutreffen.

In dem folgenden Beispiel wird die Tabelle Products als Zieltabelle verwendet. UpdatedProducts ist hierbei die Quelltabelle. Diese hat Produktinformationen, die noch nicht in Products vorhanden sind. Anschließend werden wir den MERGE Befehl verwenden, um diese Differenz an Daten zu beheben.

Beispiel:

Erstellen wir zuerst die Tabellen und füllen sie mit Beispielwerten:

--MERGE SQL statement - Part 1

--Create a target table
CREATE TABLE Products
(
   ProductID INT PRIMARY KEY,
   ProductName VARCHAR(100),
   Rate MONEY
) 
GO

--Insert records into target table
INSERT INTO Products
VALUES
   (1, 'Tea', 10.00),
   (2, 'Coffee', 20.00),
   (3, 'Muffin', 30.00),
   (4, 'Biscuit', 40.00)
GO

--Create source table
CREATE TABLE UpdatedProducts
(
   ProductID INT PRIMARY KEY,
   ProductName VARCHAR(100),
   Rate MONEY
) 
GO

--Insert records into source table
INSERT INTO UpdatedProducts
VALUES
   (1, 'Tea', 10.00),
   (2, 'Coffee', 25.00),
   (3, 'Muffin', 35.00),
   (5, 'Pizza', 60.00)
GO

SELECT * FROM Products
SELECT * FROM UpdatedProducts
GO

Nun wird, wie angekündigt, der MERGE Befehl verwendet, um die Tabellen zu synchronisieren:

--MERGE SQL statement - Part 2

--Synchronize the target table with refreshed data from source table
MERGE Products AS TARGET
USING UpdatedProducts AS SOURCE 
ON (TARGET.ProductID = SOURCE.ProductID) 
--When records are matched, update the records if there is any change
WHEN MATCHED AND TARGET.ProductName <> SOURCE.ProductName OR TARGET.Rate <> SOURCE.Rate 
THEN UPDATE SET TARGET.ProductName = SOURCE.ProductName, TARGET.Rate = SOURCE.Rate 
--When no records are matched, insert the incoming records from source table to target table
WHEN NOT MATCHED BY TARGET 
THEN INSERT (ProductID, ProductName, Rate) VALUES (SOURCE.ProductID, SOURCE.ProductName, SOURCE.Rate)
--When there is a row that exists in target and same record does not exist in source then delete this record target
WHEN NOT MATCHED BY SOURCE 
THEN DELETE 
--$action specifies a column of type nvarchar(10) in the OUTPUT clause that returns 
--one of three values for each row: 'INSERT', 'UPDATE', or 'DELETE' according to the action that was performed on that row
OUTPUT $action, 
DELETED.ProductID AS TargetProductID, 
DELETED.ProductName AS TargetProductName, 
DELETED.Rate AS TargetRate, 
INSERTED.ProductID AS SourceProductID, 
INSERTED.ProductName AS SourceProductName, 
INSERTED.Rate AS SourceRate; 

SELECT @@ROWCOUNT;
GO

Wenn Sie diesen Befehl ausführen sehen Sie, dass es 2 Updates, 1 Delete und 1 Insert gab.

Mainzer Datenfabrik - T-SQL - Der MERGE Befehl

Wenn wir nun die Products Tabelle ausgeben lassen, sehen wir das Ergebnis des MERGE Befehls.

Der MERGE Befehl - Tipps und worauf zu achten ist

  • Der MERGE Befehl benötigt ein ; als terminierendes Zeichen. Andernfalls wirft die SQL Instanz den Error 10713: “statement is executed without the statement terminator.“
  • @@Rowcount gibt in dem Kontext die Anzahl der Tabellen wieder, die verändert wurden.
  • Die Person, die den MERGE Befehl ausführt, muss über die SELECT, INSERT, UPDATE und DELETE Berechtigungen auf den jeweiligen Tabellen verfügen.
  • Der MERGE Befehl verbessert die Performance im Vergleich zur Ausführung der drei separaten Befehle, da die Daten nur einmal, und nicht dreifach verarbeitet werden.
  • Für jede ausgeführte INSERT, UPDATE oder DELETE Aktion die durch den MERGE Befehl ausgeführt wird, wird der jeweilige Trigger ebenso vollstreckt - soweit einer konfiguriert ist.

Fazit##

Abschließend lässt sich sagen, dass MERGE einen elementaren Befehl für die Synchronisation von Daten bereitstellt. Zwar kann es zu Schwierigkeiten kommen den Befehl einmal richtig zu konfigurieren, doch bringt er einen enormen Vorteil gegenüber der Alternative. Falls es bei der Verwendung zu Problemen kommen sollte, zögern Sie nicht uns über unser Kontaktformular zu kontaktieren.

Interesse geweckt?

Unsere Expert:innen stehen Ihnen bei allen Fragen rund um Ihre IT Infrastruktur zur Seite.

Kontaktieren Sie uns gerne über das Kontaktformular und vereinbaren ein unverbindliches Beratungsgespräch mit unseren Berater:innen zur Bedarfsevaluierung. Gemeinsam optimieren wir Ihre Umgebung und steigern Ihre Performance!
Wir freuen uns auf Ihre Kontaktaufnahme!

Taunusstraße 72
55118 Mainz
info@madafa.de
+49 6131 3331612
Bürozeiten
Montag bis Donnerstag:
9:00 - 17:00 Uhr MEZ

Freitags:
9:30 - 14:00 Uhr MEZ