Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Gilt für:SQL Server
Azure SQL Database
Azure SQL Managed Instance
Azure Synapse Analytics (dedicated SQL pool only)
SQL-Datenbank in Microsoft Fabric
Lager in Microsoft Fabric
Die MERGE Anweisung führt Einfüge-, Aktualisierungs- oder Löschvorgänge für eine Zieltabelle aus den Ergebnissen einer Verknüpfung mit einer Quelltabelle aus. Synchronisieren Sie z.B. zwei Tabellen, indem Sie Zeilen in einer Tabelle anhand von Unterschieden, die in der anderen Tabelle gefunden wurden, einfügen, aktualisieren oder löschen.
Dieser Artikel enthält verschiedene Syntax, Argumente, Hinweise, Berechtigungen und Beispiele basierend auf der ausgewählten Produktversion. Wählen Sie ihre gewünschte Produktversion aus der Dropdownliste der Version aus.
Note
In Fabric Data Warehouse MERGE befindet sich die Vorschau.
Transact-SQL-Syntaxkonventionen
Syntax
Syntax für SQL Server und Azure SQL-Datenbank:
[ WITH <common_table_expression> [,...n] ]
MERGE
[ TOP ( expression ) [ PERCENT ] ]
[ INTO ] <target_table> [ WITH ( <merge_hint> ) ] [ [ AS ] table_alias ]
USING <table_source> [ [ AS ] table_alias ]
ON <merge_search_condition>
[ WHEN MATCHED [ AND <clause_search_condition> ]
THEN <merge_matched> ] [ ...n ]
[ WHEN NOT MATCHED [ BY TARGET ] [ AND <clause_search_condition> ]
THEN <merge_not_matched> ]
[ WHEN NOT MATCHED BY SOURCE [ AND <clause_search_condition> ]
THEN <merge_matched> ] [ ...n ]
[ <output_clause> ]
[ OPTION ( <query_hint> [ ,...n ] ) ]
;
<target_table> ::=
{
[ database_name . schema_name . | schema_name . ] [ [ AS ] target_table ]
| @variable [ [ AS ] target_table ]
| common_table_expression_name [ [ AS ] target_table ]
}
<merge_hint>::=
{
{ [ <table_hint_limited> [ ,...n ] ]
[ [ , ] { INDEX ( index_val [ ,...n ] ) | INDEX = index_val }]
}
}
<merge_search_condition> ::=
<search_condition>
<merge_matched>::=
{ UPDATE SET <set_clause> | DELETE }
<merge_not_matched>::=
{
INSERT [ ( column_list ) ]
{ VALUES ( values_list )
| DEFAULT VALUES }
}
<clause_search_condition> ::=
<search_condition>
Syntax für Azure Synapse Analytics, Fabric Data Warehouse:
[ WITH <common_table_expression> [,...n] ]
MERGE
[ INTO ] <target_table> [ [ AS ] table_alias ]
USING <table_source> [ [ AS ] table_alias ]
ON <merge_search_condition>
[ WHEN MATCHED [ AND <clause_search_condition> ]
THEN <merge_matched> ] [ ...n ]
[ WHEN NOT MATCHED [ BY TARGET ] [ AND <clause_search_condition> ]
THEN <merge_not_matched> ]
[ WHEN NOT MATCHED BY SOURCE [ AND <clause_search_condition> ]
THEN <merge_matched> ] [ ...n ]
[ OPTION ( <query_hint> [ ,...n ] ) ]
; -- The semi-colon is required, or the query will return a syntax error.
<target_table> ::=
{
[ database_name . schema_name . | schema_name . ]
target_table
}
<merge_search_condition> ::=
<search_condition>
<merge_matched>::=
{ UPDATE SET <set_clause> | DELETE }
<merge_not_matched>::=
{
INSERT [ ( column_list ) ]
VALUES ( values_list )
}
<clause_search_condition> ::=
<search_condition>
Arguments
MIT <common_table_expression>
Gibt den temporären benannten Resultset oder die Ansicht an, der auch als allgemeiner Tabellenausdruck bezeichnet wird, der innerhalb des Bereichs der MERGE Anweisung definiert ist. Das Resultset wird von einer einfachen Abfrage abgeleitet und von der MERGE Anweisung referenziert. Weitere Informationen finden Sie unter WITH common_table_expression (Transact-SQL).
TOP ( Ausdruck ) [ PERCENT ]
Gibt die Anzahl oder den Prozentsatz der betroffenen Zeilen an.
expression kann eine Anzahl oder ein Prozentsatz der Zeilen sein. Die zeilen, auf die TOP im Ausdruck verwiesen wird, sind in keiner Reihenfolge angeordnet. Weitere Informationen finden Sie unter TOP (Transact-SQL).
Die TOP Klausel gilt nach der gesamten Quelltabelle und der gesamten Zieltabellenbeitritt und den verknüpften Zeilen, die sich nicht für eine Einfüge-, Aktualisierungs- oder Löschaktion qualifizieren, werden entfernt. Die TOP Klausel reduziert die Anzahl der verknüpften Zeilen weiter auf den angegebenen Wert. Diese Aktionen (Einfügen, Aktualisieren oder Löschen) gelten in ungeordneter Weise für die übrigen verknüpften Zeilen. Das heißt, es gibt keine Reihenfolge, in der die Zeilen zwischen den in den WHEN Klauseln definierten Aktionen verteilt werden. Beispielsweise wirkt sich die Angabe TOP (10) auf 10 Zeilen aus. Von diesen Zeilen können 7 aktualisiert und 3 eingefügt werden, oder 1 Zeile kann gelöscht, 5 können aktualisiert und 4 eingefügt werden usw.
Ohne Filter in der Quelltabelle führt die MERGE Anweisung möglicherweise eine Tabellenüberprüfung oder einen Gruppierten Indexscan in der Quelltabelle sowie eine Tabellenüberprüfung oder einen Gruppierten Indexscan der Zieltabelle durch. Daher ist die E/A-Leistung manchmal auch dann betroffen, wenn die TOP Klausel zum Ändern einer großen Tabelle verwendet wird, indem mehrere Batches erstellt werden. In diesem Szenario muss unbedingt sichergestellt werden, dass alle aufeinanderfolgenden Batches auf neue Zeilen ausgerichtet sind.
database_name
Der Name der Datenbank, in der sich target_table befindet.
schema_name
Der Namen des Schemas, zu dem die Tabelle target_table gehört.
target_table
Hiermit wird die Tabelle oder die Ansicht angegeben, mit der die Datenzeilen aus <table_source> basierend auf <clause_search_condition> abgeglichen werden.
target_table ist das Ziel von Einfüge-, Aktualisierungs- oder Löschvorgängen, die durch die WHEN Klauseln der MERGE Anweisung angegeben werden.
Wenn target_table eine Sicht ist, müssen alle Aktionen für die Tabelle die Bedingungen zum Aktualisieren von Sichten erfüllen. Weitere Informationen finden Sie unter Modify Data Through a View (Ändern von Daten über eine Sicht).
target_table darf keine Remotetabelle sein. Für target_table dürfen keine Regeln definiert sein. target_table darf keine speicheroptimierte Tabelle sein.
Hinweise können als <merge_hint> angegeben werden.
<merge_hint> wird für Azure Synapse Analytics nicht unterstützt.
[ AS ] table_alias
Dies ist ein alternativer Name zum Verweisen auf eine Tabelle für target_table.
MIT <table_source>
Hiermit wird die Datenquelle angegeben, die basierend auf mit den Datenzeilen in <merge_search_condition> abgeglichen wird. Das Ergebnis dieser Übereinstimmung bestimmt die Aktionen, die von den WHEN Klauseln der MERGE Anweisung ausgeführt werden sollen.
<table_source> kann eine Remotetabelle oder eine abgeleitete Tabelle sein, die auf Remotetabellen zugreift.
<table_source> kann eine abgeleitete Tabelle sein, die mit dem Tabellenwertkonstruktur von Transact-SQL durch Angabe mehrerer Zeilen eine Tabelle erstellt.
<table_source> kann eine abgeleitete Tabelle sein, die mit SELECT ... UNION ALL eine Tabelle durch Angeben mehrerer Zeilen erstellt.
[ AS ] table_alias
Dies ist ein alternativer Name zum Verweisen auf eine Tabelle für table_source.
Weitere Informationen zur Syntax und zu den Argumenten dieser Klausel finden Sie unter FROM (Transact-SQL).
AUF <merge_search_condition>
Hiermit werden die Bedingungen angegeben, unter denen <table_source> mit target_table verknüpft wird, um Übereinstimmungen zu ermitteln.
Caution
Es ist wichtig, dass nur die Spalten aus der Zieltabelle angegeben werden, die für Abgleichszwecke verwendet werden. Geben Sie also Spalten aus der Zieltabelle an, die mit der entsprechenden Spalte der Quelltabelle abgeglichen werden. Versuchen Sie nicht, die Abfrageleistung zu verbessern, indem Sie Zeilen in der Zieltabelle in der ON Klausel herausfiltern, z. B. angeben AND NOT target_table.column_x = value. Dadurch kann es zu unerwarteten und falschen Ergebnissen kommen.
WENN DIE ÜBEREINSTIMMUNG DANN <MERGE_MATCHED>
Gibt an, dass alle Zeilen von *target_table, die den zeilen entsprechen, die zurückgegeben <table_source> ON <merge_search_condition>werden, und alle zusätzlichen Suchbedingung erfüllen, entweder aktualisiert oder gemäß der <merge_matched> Klausel gelöscht werden.
Die MERGE Anweisung kann höchstens zwei WHEN MATCHED Klauseln aufweisen. Wenn zwei Klauseln angegeben sind, muss die erste Klausel von einer AND<search_condition> Klausel begleitet werden. Bei einer bestimmten Zeile wird die zweite WHEN MATCHED Klausel nur angewendet, wenn die erste nicht der Fall ist. Wenn zwei WHEN MATCHED Klauseln vorhanden sind, muss eine Aktion angegeben UPDATE werden, und eine muss eine DELETE Aktion angeben. Wenn UPDATE in der <merge_matched> Klausel angegeben wird und mehr als eine Zeile <table_source> mit einer Zeile in target_table basierend auf <merge_search_condition>, gibt SQL Server einen Fehler zurück. Die MERGE Anweisung kann dieselbe Zeile nicht mehr als einmal aktualisieren oder dieselbe Zeile aktualisieren und löschen.
WENN NICHT MIT [NACH ZIEL] ÜBEREINSTIMMT, <MERGE_NOT_MATCHED>
Gibt an, dass eine Zeile in target_table für jede Zeile eingefügt wird, die von <table_source> ON <merge_search_condition> dieser zurückgegeben wird, nicht mit einer Zeile in target_table übereinstimmt, aber eine zusätzliche Suchbedingung erfüllt, sofern vorhanden. Die einzufügenden Werte werden durch die <merge_not_matched>-Klausel angegeben. Die MERGE Anweisung kann nur eine WHEN NOT MATCHED [ BY TARGET ] Klausel aufweisen.
WENN NICHT VON DER QUELLE ABGEGLICHEN WIRD, <MERGE_MATCHED>
Gibt an, dass alle Zeilen von *target_table, die nicht mit den zeilen übereinstimmen, die <table_source> ON <merge_search_condition>zurückgegeben werden, und die alle zusätzlichen Suchbedingungen erfüllen, gemäß der <merge_matched> Klausel aktualisiert oder gelöscht werden.
Die MERGE Anweisung kann höchstens zwei WHEN NOT MATCHED BY SOURCE Klauseln aufweisen. Wenn zwei Klauseln angegeben sind, muss die erste Klausel von einer AND<clause_search_condition> Klausel begleitet werden. Bei einer bestimmten Zeile wird die zweite WHEN NOT MATCHED BY SOURCE Klausel nur angewendet, wenn die erste nicht der Fall ist. Wenn zwei WHEN NOT MATCHED BY SOURCE Klauseln vorhanden sind, muss eine Aktion angegeben UPDATE werden, und eine muss eine DELETE Aktion angeben. In <clause_search_condition> kann nur auf Spalten aus der Zieltabelle verwiesen werden.
Wenn von <table_source> keine Zeilen zurückgegeben werden, kann auf Spalten in der Quelltabelle nicht zugegriffen werden. Wenn die in der <merge_matched>-Klausel angegebene Update- oder Löschaktion auf Spalten in der Quelltabelle verweist, wird der Fehler 207 (Ungültiger Spaltenname) zurückgegeben. Die Klausel WHEN NOT MATCHED BY SOURCE THEN UPDATE SET TargetTable.Col1 = SourceTable.Col1 kann beispielsweise dazu führen, dass die Anweisung fehlschlägt, da der Zugriff auf Col1 in der Quelltabelle nicht möglich ist.
UND <clause_search_condition>
Gibt jede gültige Suchbedingung an. Weitere Informationen finden Sie unter Suchbedingung (Transact-SQL).
<table_hint_limited>
Gibt einen oder mehrere Tabellenhinweise an, die für die Zieltabelle für jedes der von der MERGE Anweisung ausgeführten Einfüge-, Aktualisierungs- oder Löschaktionen angewendet werden sollen. Das WITH Schlüsselwort und die Klammern sind erforderlich.
NOLOCK und READUNCOMMITTED sind nicht zulässig. Weitere Informationen zu Tabellenhinweisen finden Sie unter "Tabellenhinweise(Transact-SQL)".
Das Angeben des TABLOCK Hinweises auf eine Tabelle, die das Ziel einer INSERT Anweisung ist, hat die gleiche Auswirkung wie das Angeben des TABLOCKX Hinweises. Auf die Tabelle wird eine exklusive Sperre angewendet. Wenn FORCESEEK angegeben wird, wird der Hinweis auf die implizite Instanz der Zieltabelle angewendet, die mit der Quelltabelle verknüpft ist.
Caution
Die Angabe READPAST kann WHEN NOT MATCHED [ BY TARGET ] THEN INSERT zu INSERT Vorgängen führen, die gegen Einschränkungen verstoßen UNIQUE .
INDEX ( index_val [ ,... n ] )
Gibt den Namen oder die ID eines oder mehrerer Indizes in der Zieltabelle zum Ausführen eines impliziten Joins mit der Quelltabelle an. Weitere Informationen finden Sie unter Tabellenhinweise (Transact-SQL).
<output_clause>
Gibt ohne bestimmte Reihenfolge eine Zeile für jede Zeile in target_table zurück, die aktualisiert, eingefügt oder gelöscht wird.
$action kann in der Ausgabe-Klausel angegeben werden.
$action ist eine Spalte vom Typ nvarchar(10), die für jede Zeile einen von drei Werten zurückgibt: „INSERT“, „UPDATE“ oder „DELETE“, je nach der für diese Zeile ausgeführten Aktion. Die OUTPUT Klausel ist die empfohlene Methode zum Abfragen oder Zählen von Zeilen, die von einer .MERGE Weitere Informationen zu den Argumenten und dem Verhalten dieser Klausel finden Sie unter OUTPUT-Klausel (Transact-SQL).
OPTION ( <query_hint> [ ,... n ] )
Gibt an, dass mithilfe von Optimierungshinweisen angepasst wird, wie die Anweisung von Datenbank-Engine verarbeitet wird. Weitere Informationen finden Sie unter Abfragehinweise (Transact-SQL).
<merge_matched>
Gibt die Aktualisierungs- oder Löschaktion an, die auf alle Zeilen von target_table angewendet wird, die nicht mit den zeilen übereinstimmen, die zurückgegeben <table_source> ON <merge_search_condition>werden, und die eine zusätzliche Suchbedingung erfüllen.
UPDATE GESETZT <set_clause>
Gibt die Liste der Spalten- oder Variablennamen an, die in der Zieltabelle aktualisiert werden sollen, sowie die Werte, mit denen das Update vorgenommen werden soll.
Weitere Informationen zu den Argumenten dieser Klausel finden Sie unter UPDATE (Transact-SQL). Eine Variable auf denselben Wert festzulegen wie eine Spalte wird nicht unterstützt.
DELETE
Gibt an, dass die Zeilen, die mit Zeilen in target_table übereinstimmen, gelöscht werden.
<merge_not_matched>
Gibt die Werte an, die in die Zieltabelle eingefügt werden sollen.
( column_list )
Eine Liste mit einer oder mehreren Spalten der Zieltabelle, in die Daten eingefügt werden sollen. Spalten müssen als einteiliger Name angegeben werden, sonst schlägt die MERGE Anweisung fehl.
column_list muss in Klammern eingeschlossen und durch ein Trennzeichen getrennt werden.
VALUES ( values_list)
Eine durch Trennzeichen getrennte Liste mit Konstanten, Variablen oder Ausdrücken, die Werte zum Einfügen in die Zieltabelle zurückgeben. Ausdrücke können keine Anweisung enthalten EXECUTE .
STANDARDWERTE
Erzwingt, dass die eingefügte Zeile den für jede Spalte definierten Standardwert enthält.
Weitere Informationen zu dieser Klausel finden Sie unter INSERT (Transact-SQL).
<search_condition>
Hiermit werden die Suchbedingungen zum Angeben von <merge_search_condition> oder <clause_search_condition> angegeben. Weitere Informationen zu den Argumenten für diese Klausel finden Sie unter Suchbedingung (Transact-SQL).
<Diagrammsuchmuster>
Gibt das Graph-Vergleichsmuster an. Weitere Informationen zu den Argumenten für diese Klausel finden Sie unter MATCH (Transact-SQL).
Remarks
Das für die MERGE Anweisung beschriebene bedingte Verhalten funktioniert am besten, wenn die beiden Tabellen eine komplexe Mischung aus übereinstimmenden Merkmalen aufweisen. Beispielsweise das Einfügen einer Zeile, wenn sie nicht vorhanden ist, oder das Aktualisieren der Zeile, wenn sie übereinstimmt. Wenn Sie einfach eine Tabelle basierend auf den Zeilen einer anderen Tabelle aktualisieren, verbessern Sie die Leistung und Skalierbarkeit mit INSERT, UPDATEund DELETE Anweisungen. Beispiel:
INSERT tbl_A (col, col2)
SELECT col, col2
FROM tbl_B
WHERE NOT EXISTS (SELECT col FROM tbl_A A2 WHERE A2.col = tbl_B.col);
Mindestens eine der drei MATCHED Klauseln muss angegeben werden, kann jedoch in beliebiger Reihenfolge angegeben werden. Eine Variable kann nicht mehrmals in derselben MATCHED Klausel aktualisiert werden.
Alle in der Zieltabelle durch die MERGE Anweisung angegebenen Einfüge-, Aktualisierungs- oder Löschaktionen sind durch alle darin definierten Einschränkungen beschränkt, einschließlich cascading referential integrity constraints.
IGNORE_DUP_KEY Wenn ON für eindeutige Indizes in der Zieltabelle gilt, MERGE wird diese Einstellung ignoriert.
Die MERGE Anweisung erfordert ein Semikolon (;) als Anweisungsterminator. Fehler 10713 wird ausgelöst, wenn eine MERGE Anweisung ohne den Terminator ausgeführt wird.
Bei Verwendung nach MERGE, @@ROWCOUNT (Transact-SQL) gibt die Gesamtanzahl der eingefügten, aktualisierten und gelöschten Zeilen an den Client zurück.
MERGE ist ein vollständig reserviertes Schlüsselwort, wenn die Datenbankkompatibilitätsebene auf 100 oder höher festgelegt ist. Die MERGE Anweisung ist sowohl unter Datenbankkompatibilitätsebenen 90100 als auch unter Datenbankkompatibilitätsebenen verfügbar. Das Schlüsselwort ist jedoch nicht vollständig reserviert, wenn die Datenbankkompatibilitätsstufe auf " 90.
Caution
Verwenden Sie die Anweisung nicht, wenn Sie die MERGE Warteschlange verwenden. Der MERGE Auslöser für die Aktualisierung in der Warteschlange ist nicht kompatibel. Ersetzen Sie die MERGE Anweisung durch eine INSERT und UPDATE Anweisungen.
Überlegungen zu Azure Synapse Analytics
In Azure Synapse Analytics weist der MERGE Befehl folgende Unterschiede im Vergleich zu SQL Server- und Azure SQL-Datenbank auf.
- Die Verwendung
MERGEzum Aktualisieren einer Verteilungsschlüsselspalte wird in Builds, die älter als 10.0.17829.0 sind, nicht unterstützt. Wenn Sie das Upgrade nicht anhalten oder erzwingen können, verwenden Sie die ANSI-AnweisungUPDATE FROM ... JOINals Problemumgehung bis zur Version 10.0.17829.0. - Eine
MERGEAktualisierung wird als Lösch- und Einfügepaar implementiert. Die anzahl der betroffenen Zeilen für eineMERGEAktualisierung umfasst die gelöschten und eingefügten Zeilen. -
MERGE...WHEN NOT MATCHED INSERTwird für Tabellen mitIDENTITYSpalten nicht unterstützt. - Der Tabellenwertkonstruktor kann in der
USINGKlausel für die Quelltabelle nicht verwendet werden. Verwenden SieSELECT ... UNION ALL, um eine abgeleitete Quelltabelle mit mehreren Zeilen zu erstellen. - Die Unterstützung für Tabellen mit verschiedenen Verteilungstypen ist in dieser Tabelle beschrieben:
| MERGE-KLAUSEL in Azure Synapse Analytics | Unterstützte TARGET Verteilungstabelle |
Unterstützte QUELL-Verteilungstabelle | Comment |
|---|---|---|---|
WHEN MATCHED |
Alle Verteilungstypen | Alle Verteilungstypen | |
NOT MATCHED BY TARGET |
HASH |
Alle Verteilungstypen | Verwenden Sie UPDATE/DELETE FROM...JOIN, um zwei Tabellen zu synchronisieren. |
NOT MATCHED BY SOURCE |
Alle Verteilungstypen | Alle Verteilungstypen |
Tip
Wenn Sie den Verteilungshashschlüssel als JOIN Spalte verwenden MERGE und nur einen Gleichheitsvergleich ausführen, können Sie den Verteilungsschlüssel aus der Liste der Spalten in der WHEN MATCHED THEN UPDATE SET Klausel weglassen, da dies eine redundante Aktualisierung ist.
In Azure Synapse Analytics kann der MERGE Befehl auf Builds, die älter als 10.0.17829.0 sind, unter bestimmten Bedingungen die Zieltabelle in einem inkonsistenten Zustand belassen, wobei Zeilen in der falschen Verteilung platziert wurden, was zu späteren Abfragen führt, dass in einigen Fällen falsche Ergebnisse zurückgegeben werden. Dieses Problem kann in zwei Fällen auftreten:
| Scenario | Comment |
|---|---|
|
Fall 1 Wird MERGE für eine verteilte TARGET HASH-Tabelle verwendet, die sekundäre Indizes oder eine UNIQUE Einschränkung enthält. |
- In Synapse SQL 10.0.15563.0 und höheren Versionen behoben. - Wenn SELECT @@VERSION eine niedrigere Version als 10.0.15563.0 zurückgegeben wird, halten Sie den Synapse SQL-Pool manuell an, und setzen Sie ihn fort, um diesen Fix aufzunehmen.– Bis der Fix auf Ihren Synapse SQL-Pool angewendet wurde, vermeiden Sie die Verwendung des MERGE Befehls für HASH verteilte TARGET Tabellen mit sekundären Indizes oder UNIQUE Einschränkungen. |
|
Fall 2 Verwenden von MERGE zum Aktualisieren einer Verteilungsschlüsselspalte einer verteilten HASH-Tabelle. |
- In Synapse SQL 10.0.17829.0 und höheren Versionen behoben. - Wenn SELECT @@VERSION eine niedrigere Version als 10.0.17829.0 zurückgegeben wird, halten Sie den Synapse SQL-Pool manuell an, und setzen Sie ihn fort, um diesen Fix aufzunehmen.– Bis der Fix auf Ihren Synapse SQL-Pool angewendet wurde, vermeiden Sie die Verwendung des Befehls zum Aktualisieren von MERGE Verteilungsschlüsselspalten. |
Die Updates in beiden Szenarien reparieren keine Tabellen, die bereits von der vorherigen MERGE Ausführung betroffen sind. Verwenden Sie die folgenden Skripts, um die betroffenen Tabellen manuell zu identifizieren und zu reparieren.
Führen Sie diese Anweisung aus, um zu überprüfen, welche HASH verteilten Tabellen in einer Datenbank von Bedenklich sein können (wenn sie in den oben genannten Fällen verwendet werden):
-- Case 1
SELECT a.name,
c.distribution_policy_desc,
b.type
FROM sys.tables a
INNER JOIN sys.indexes b
ON a.object_id = b.object_id
INNER JOIN sys.pdw_table_distribution_properties c
ON a.object_id = c.object_id
WHERE b.type = 2
AND c.distribution_policy_desc = 'HASH';
-- Subject to Case 2, if distribution key value is updated in MERGE statement
SELECT a.name,
c.distribution_policy_desc
FROM sys.tables a
INNER JOIN sys.pdw_table_distribution_properties c
ON a.object_id = c.object_id
WHERE c.distribution_policy_desc = 'HASH';
Um zu überprüfen, ob eine HASH verteilte Tabelle MERGE von Fall 1 oder Fall 2 betroffen ist, führen Sie die folgenden Schritte aus, um zu überprüfen, ob die Tabellen Zeilen in falsche Verteilung gelandet haben. Wenn no need for repair zurückgegeben wird, ist diese Tabelle nicht betroffen.
IF object_id('[check_table_1]', 'U') IS NOT NULL
DROP TABLE [check_table_1]
GO
IF object_id('[check_table_2]', 'U') IS NOT NULL
DROP TABLE [check_table_2]
GO
CREATE TABLE [check_table_1]
WITH (DISTRIBUTION = ROUND_ROBIN) AS
SELECT <DISTRIBUTION_COLUMN> AS x
FROM <MERGE_TABLE>
GROUP BY <DISTRIBUTION_COLUMN>;
GO
CREATE TABLE [check_table_2]
WITH (DISTRIBUTION = HASH (x)) AS
SELECT x
FROM [check_table_1];
GO
IF NOT EXISTS (
SELECT TOP 1 *
FROM (
SELECT <DISTRIBUTION_COLUMN> AS x
FROM <MERGE_TABLE>
EXCEPT
SELECT x
FROM [check_table_2]
) AS tmp
)
SELECT 'no need for repair' AS result
ELSE
SELECT 'needs repair' AS result
GO
IF object_id('[check_table_1]', 'U') IS NOT NULL
DROP TABLE [check_table_1]
GO
IF object_id('[check_table_2]', 'U') IS NOT NULL
DROP TABLE [check_table_2]
GO
Um betroffene Tabellen zu reparieren, führen Sie diese Anweisungen aus, um alle Zeilen aus der alten Tabelle in eine neue Tabelle zu kopieren.
IF object_id('[repair_table_temp]', 'U') IS NOT NULL
DROP TABLE [repair_table_temp];
GO
IF object_id('[repair_table]', 'U') IS NOT NULL
DROP TABLE [repair_table];
GO
CREATE TABLE [repair_table_temp]
WITH (DISTRIBUTION = ROUND_ROBIN) AS
SELECT *
FROM <MERGE_TABLE>;
GO
-- [repair_table] will hold the repaired table generated from <MERGE_TABLE>
CREATE TABLE [repair_table]
WITH (DISTRIBUTION = HASH (<DISTRIBUTION_COLUMN>)) AS
SELECT *
FROM [repair_table_temp];
GO
IF object_id('[repair_table_temp]', 'U') IS NOT NULL
DROP TABLE [repair_table_temp];
GO
Troubleshooting
In bestimmten Szenarien kann eine MERGE Anweisung zu dem Fehler CREATE TABLE failed because column <> in table <> exceeds the maximum of 1024 columns.führen, auch wenn die Ziel- oder Quelltabelle nicht über 1.024 Spalten verfügt. Dieses Szenario kann auftreten, wenn alle folgenden Bedingungen erfüllt sind:
- Mehrere Spalten werden in einem
DELETE,UPDATE SEToderINSERTeinem Vorgang innerhalbMERGE(nicht spezifisch für eineWHEN [NOT] MATCHEDKlausel) angegeben. - Jede Spalte in der
JOINBedingung weist einen nicht gruppierten Index (NCI) auf. - Zieltabelle wird
HASHverteilt
Wenn dieser Fehler auftritt, wird folgende Problemumgehung vorgeschlagen:
- Entfernen Sie den nicht gruppierten Index (NCI) aus den
JOINSpalten, oder verbinden Sie den Index auf Spalten ohne NCI. Wenn Sie die zugrunde liegenden Tabellen später so aktualisieren, dass sie eine NCI in dieJOINSpalten aufnehmen, ist IhreMERGEAnweisung möglicherweise zur Laufzeit anfällig für diesen Fehler. Weitere Informationen finden Sie unter DROP INDEX. - Verwenden Sie UPDATE-, DELETE- und INSERT-Anweisungen anstelle von
MERGE.
Triggerimplementierung
Für jede in der MERGE Anweisung angegebene Einfüge-, Aktualisierungs- oder Löschaktion löst SQL Server alle in der Zieltabelle definierten entsprechenden AFTER Trigger aus, garantiert jedoch nicht, welche Aktion zuerst oder zuletzt ausgelöst werden soll. Trigger, die für dieselbe Aktion definiert sind, halten sich an die von Ihnen angegebene Reihenfolge. Weitere Informationen zum Festlegen der Reihenfolge beim Auslösen von Triggern finden Sie unter Angeben des ersten und des letzten Triggers.
Wenn die Zieltabelle über einen INSTEAD aktivierten OF-Trigger verfügt, der für eine Einfüge-, Aktualisierungs- oder Löschaktion definiert ist, die von einer MERGE Anweisung ausgeführt wird, muss sie für alle in der INSTEAD Anweisung angegebenen Aktionen einen OF-Trigger MERGE aktiviert haben.
Wenn alle INSTEAD OF- UPDATE oder OF-Trigger INSTEAD für DELETE definiert sind, werden die Aktualisierungs- oder Löschvorgänge nicht ausgeführt. Stattdessen werden die Trigger ausgelöst, und die inserted- und deleted-Tabelle werden entsprechend aufgefüllt.
Wenn of-Trigger INSTEADINSERT für target_table definiert sind, wird der Einfügevorgang nicht ausgeführt. Stattdessen wird die Tabelle entsprechend aufgefüllt.
Note
Im Gegensatz zu separaten INSERT, UPDATEund DELETE Anweisungen kann die Anzahl der Zeilen, die innerhalb @@ROWCOUNT eines Triggers angezeigt werden, höher sein. Der @@ROWCOUNT innerhalb eines AFTER Triggers (unabhängig von Datenänderungsanweisungen, die der Trigger erfasst) entspricht der Gesamtanzahl der zeilen, die von der MERGEBetroffenen betroffen sind. Wenn eine MERGE Anweisung z. B. eine Zeile einfügt, eine Zeile aktualisiert und eine Zeile löscht, @@ROWCOUNT wird für jeden AFTER Trigger drei angegeben, auch wenn der Trigger nur für INSERT Anweisungen deklariert ist.
Permissions
Erfordert SELECT Berechtigungen für die Quelltabelle und INSERT, UPDATEoder DELETE Berechtigungen für die Zieltabelle. Weitere Informationen finden Sie im Abschnitt "Berechtigungen" in den Artikeln SELECT (Transact-SQL), INSERT (Transact-SQL), UPDATE (Transact-SQL) und DELETE (Transact-SQL) Artikel.
Bewährte Methoden zum Indizieren
Mithilfe der MERGE Anweisung können Sie die einzelnen DML-Anweisungen durch eine einzelne Anweisung ersetzen. Auf diese Weise können Sie die Abfrageleistung verbessern, da die Vorgänge innerhalb einer einzelnen Anweisung ausgeführt und so die Anzahl der Verarbeitungsvorgänge für die Daten in der Quell- und Zieltabelle minimiert werden. Leistungssteigerungen sind jedoch von richtigen Indizes, Joins und anderen Fragen abhängig.
Um die Leistung der MERGE Anweisung zu verbessern, empfehlen wir die folgenden Indexrichtlinien:
- Erstellen Sie Indizes, um die Verknüpfung zwischen der Quelle und dem Ziel der
MERGE:- Erstellen Sie einen Index für die Verknüpfungsspalten in der Quelltabelle mit Schlüsseln, die die Verknüpfungslogik für die Zieltabelle abdecken. Wenn möglich, sollte er eindeutig sein.
- Erstellen Sie außerdem einen Index für die Verknüpfungsspalten in der Zieltabelle. Falls möglich, sollte es sich um einen eindeutigen gruppierten Index handeln.
- Diese beiden Indizes stellen sicher, dass die Daten in den Tabellen sortiert sind, und Eindeutigkeit unterstützt die Leistung des Vergleichs. Die Abfrageleistung wird verbessert, da der Abfrageoptimierer keine zusätzliche Validierung ausführen muss, um doppelte Zeilen zu suchen und zu aktualisieren, und zusätzliche Sortiervorgänge nicht erforderlich sind.
- Vermeiden Sie Tabellen mit einer beliebigen Form von Columnstore-Index als Ziel von
MERGEAnweisungen. Wie bei allen UPDATEs finden Sie möglicherweise eine bessere Leistung mit Spaltenspeicherindizes, indem Sie eine mehrstufige Rowstore-Tabelle aktualisieren und dann einen BatchDELETEausführen undINSERTanstelle eines oderUPDATE.MERGE
Parallelitätsüberlegungen für MERGE
Bei der Sperrung MERGE unterscheidet sich dies von diskreten, aufeinander folgenden INSERTund UPDATEDELETEAnweisungen.
MERGE führt INSERTweiterhin , UPDATEund DELETE Vorgänge, jedoch mit unterschiedlichen Sperrmechanismen. Möglicherweise ist es effizienter, diskrete INSERT, UPDATEund DELETE Anweisungen für einige Anwendungsanforderungen zu schreiben. Im großen Maßstab MERGE können komplizierte Parallelitätsprobleme auftreten oder eine erweiterte Problembehandlung erforderlich sein. Planen Sie daher, alle MERGE Anweisungen gründlich zu testen, bevor Sie sie in der Produktion bereitstellen.
MERGE Anweisungen sind ein geeigneter Ersatz für diskrete INSERT, UPDATEund DELETE Vorgänge in (aber nicht beschränkt auf) die folgenden Szenarien:
- ETL-Vorgänge mit einer großen Zeilenanzahl werden zu einer Uhrzeit ausgeführt, in der andere gleichzeitige Vorgänge nicht* erwartet werden. Wenn eine hohe Parallelität erwartet wird, können separate
INSERT,UPDATEundDELETELogik besser funktionieren, mit weniger Blockierung als eineMERGEAnweisung. - Komplexe Vorgänge mit geringer Zeilenanzahl und Transaktionen, die für längere Zeit wahrscheinlich nicht ausgeführt werden.
- Komplexe Vorgänge mit Benutzertabellen, bei denen Indizes so gestaltet werden können, dass sie optimale Ausführungspläne gewährleisten, indem Tabellenscans und Lookups zugunsten von Indexscans oder – im Idealfall – Indexsuchvorgängen vermieden werden.
Weitere Überlegungen zur Parallelität:
- In einigen Szenarien, in denen eindeutige Schlüssel erwartet werden, dass sie sowohl eingefügt als auch aktualisiert werden
MERGE, indem angegeben wird, dass diesHOLDLOCKgegen Verstöße gegen eindeutige Schlüssel verstößt.HOLDLOCKist ein Synonym für dieSERIALIZABLETransaktionsisolationsstufe, die es anderen gleichzeitigen Transaktionen nicht ermöglicht, Daten zu ändern, die diese Transaktion gelesen hat.SERIALIZABLEist die sicherste Isolationsstufe, bietet jedoch die geringste Parallelität mit anderen Transaktionen, die Sperrungen für Datenbereiche beibehalten, um zu verhindern, dass Phantomzeilen eingefügt oder aktualisiert werden, während Lesevorgänge ausgeführt werden. Weitere InformationenHOLDLOCKfinden Sie unter Tabellenhinweise und SET TRANSACTION ISOLATION LEVEL (Transact-SQL).
Bewährte Methoden für JOIN
Um die Leistung der MERGE Anweisung zu verbessern und sicherzustellen, dass korrekte Ergebnisse erzielt werden, empfehlen wir die folgenden Verknüpfungsrichtlinien:
- Geben Sie nur Suchbedingungen in der
ON <merge_search_condition>Klausel an, die die Kriterien für übereinstimmende Daten in den Quell- und Zieltabellen bestimmen. Geben Sie also nur Spalten aus der Zieltabelle an, die mit den entsprechenden Spalten der Quelltabelle verglichen werden. - Fügen Sie keine Vergleiche mit anderen Werten, z. B. einer Konstante, ein.
Zum Filtern von Zeilen aus der Quell- oder Zieltabelle verwenden Sie eine der folgenden Methoden:
- Geben Sie die Suchbedingung für die Zeilenfilterung in der entsprechenden
WHENKlausel an. Beispiel:WHEN NOT MATCHED AND S.EmployeeName LIKE 'S%' THEN INSERT.... - Definieren Sie in der Quelle oder im Ziel eine Sicht, die die gefilterten Zeilen zurückgibt, und verweisen Sie auf die Sicht als Quell- oder Zieltabelle. Wenn die Sicht für die Zieltabelle definiert ist, müssen alle Aktionen für die Tabelle die Bedingungen zum Aktualisieren von Sichten erfüllen. Weitere Informationen zum Aktualisieren von Daten mithilfe einer Ansicht finden Sie unter Ändern von Daten über eine Ansicht.
- Mit der
WITH <common table expression>-Klausel können Sie Zeilen aus den Quell- oder Zieltabellen filtern. Diese Methode ähnelt dem Angeben zusätzlicher Suchkriterien in derONKlausel und kann zu falschen Ergebnissen führen. Es wird empfohlen, die Verwendung dieser Methode zu vermeiden oder diese vor der Implementierung gründlich zu testen.
Der Verknüpfungsvorgang in der MERGE Anweisung ist genauso optimiert wie eine Verknüpfung in einer SELECT Anweisung. Das heißt, beim Verarbeiten von Joins durch SQL Server wählt der Abfrageoptimierer (aus verschiedenen Möglichkeiten) die effizienteste Methode aus. Wenn Quelle und Ziel von ähnlicher Größe sind und die zuvor beschriebenen Indizierungsrichtlinien auf die Quell- und Zieltabellen angewendet werden, bildet ein Merge Join-Operator den effizientesten Abfrageplan. Das liegt daran, dass beide Tabellen einmal durchsucht werden und anschließend keine Notwendigkeit vorliegt, die Daten zu sortieren. Wenn die Quelltabelle kleiner als die Zieltabelle ist, ist ein Nested Loops-Operator vorzuziehen.
Sie können die Verwendung einer bestimmten Verknüpfung erzwingen, indem Sie die OPTION (<query_hint>) Klausel in der MERGE Anweisung angeben. Es wird empfohlen, die Hash-Verknüpfung nicht als Abfragehinweis für MERGE Anweisungen zu verwenden, da dieser Verknüpfungstyp keine Indizes verwendet.
Bewährte Methoden für die Parametrisierung
Wenn ein , SELECT, INSERT, oder UPDATE eine DELETEAnweisung ohne Parameter ausgeführt wird, kann der SQL Server-Abfrageoptimierer die Anweisung intern parametrisieren. Dies bedeutet, dass alle eventuell in der Abfrage enthaltenen Literalwerte durch Parameter ersetzt werden. Beispielsweise kann die Anweisung INSERT dbo.MyTable (Col1, Col2) VALUES (1, 10) intern als INSERT dbo.MyTable (Col1, Col2) VALUES (@p1, @p2) implementiert werden. Dieser als einfache Parametrisierung bezeichnete Vorgang erhöht die Wahrscheinlichkeit, dass die relationale Engine neue SQL-Anweisungen vorhandenen, zuvor kompilierten Ausführungsplänen zuordnet. Möglicherweise wird die Abfrageleistung verbessert, da die Häufigkeit der Abfragekompilierungen und Neukompilierungen reduziert wird. Der Abfrageoptimierer wendet den einfachen Parameterisierungsprozess nicht auf Anweisungen an MERGE . Daher werden Anweisungen, die Literalwerte enthalten, MERGE möglicherweise nicht ausgeführt und einzelne INSERT, oder UPDATE Anweisungen, DELETEda jedes Mal, wenn die MERGE Anweisung ausgeführt wird, ein neuer Plan kompiliert wird.
Um die Abfrageleistung zu verbessern, werden die folgenden Parametrisierungsrichtlinien empfohlen:
- Parametrisieren Sie alle Literalwerte in der
ON <merge_search_condition>Klausel und in denWHENKlauseln derMERGEAnweisung. Sie können beispielsweise dieMERGEAnweisung in eine gespeicherte Prozedur integrieren, indem Sie die Literalwerte durch entsprechende Eingabeparameter ersetzen. - Wenn Sie die Anweisung nicht parametrisieren können, erstellen Sie eine Planhinweisliste vom Typ
TEMPLATE, und geben Sie in der Planhinweisliste den AbfragehinweisPARAMETERIZATION FORCEDan. Weitere Informationen finden Sie unter Angeben des Abfrageparametrisierungsverhaltens mithilfe von Planhinweislisten. - Wenn
MERGEAnweisungen häufig in der Datenbank ausgeführt werden, sollten Sie diePARAMETERIZATIONOption für die Datenbank auf festlegenFORCED. Legen Sie diese Option mit Bedacht fest. DiePARAMETERIZATION-Option ist eine Einstellung auf Datenbankebene und wirkt sich auf die Verarbeitung aller Abfragen für die Datenbank aus. Weitere Informationen finden Sie unter Erzwungene Parametrisierung. - Als neuere und einfachere Alternative zu Planhinweislisten sollten Sie eine ähnliche Strategie mit Abfragespeicherhinweisen erwägen. Weitere Informationen finden Sie unter Abfragespeicherhinweise.
Bewährte Methoden für die TOP-Klausel
In der MERGE Anweisung gibt die TOP Klausel die Anzahl oder den Prozentsatz der Zeilen an, die nach der Quelltabelle und der Zieltabelle betroffen sind, und nach Zeilen, die sich nicht für ein Einfügen, Aktualisieren oder Löschen qualifizieren, entfernt werden. Die TOP Klausel reduziert außerdem die Anzahl der verknüpften Zeilen auf den angegebenen Wert, und die Einfüge-, Aktualisierungs- oder Löschaktionen werden auf die verbleibenden verknüpften Zeilen in ungeordneter Weise angewendet. Das heißt, es gibt keine Reihenfolge, in der die Zeilen zwischen den in den WHEN Klauseln definierten Aktionen verteilt werden. Beispielsweise wirkt sich die Angabe TOP (10) auf 10 Zeilen aus; von diesen Zeilen kann 7 aktualisiert und 3 eingefügt werden, oder 1 kann gelöscht, 5 aktualisiert und 4 eingefügt usw. werden.
Es ist üblich, die TOP Klausel zum Ausführen von DML-Vorgängen (Data Manipulation Language) für eine große Tabelle in Batches zu verwenden. Wenn Sie die Klausel in der TOPMERGE Anweisung zu diesem Zweck verwenden, ist es wichtig, die folgenden Auswirkungen zu verstehen.
Die E/A-Leistung ist möglicherweise betroffen.
Die
MERGEAnweisung führt einen vollständigen Tabellenscan der Quell- und Zieltabellen durch. Durch Aufteilung des Vorgangs in Batches wird die Anzahl der Schreibvorgänge pro Batch reduziert. Für jeden Batch wird jedoch ein vollständiger Tabellenscan der Quell- und der Zieltabelle ausgeführt. Die daraus resultierende Leseaktivität kann die Leistung der Abfrage und anderer gleichzeitiger Aktivitäten in den Tabellen beeinträchtigen.Es können falsche Ergebnisse auftreten.
Es sollte unbedingt sichergestellt werden, dass alle aufeinander folgenden Batches neuen Zeilen zugeordnet sind, andernfalls kann ein unerwünschtes Verhalten auftreten, z. B. das Einfügen doppelter Zeilen in die Zieltabelle. Dies kann der Fall sein, wenn die Quelltabelle eine Zeile enthält, die nicht im Zielbatch, aber in der Zieltabelle insgesamt enthalten war. So stellen Sie die Richtigkeit der Ergebnisse sicher
- Verwenden Sie die
ONKlausel, um zu bestimmen, welche Quellzeilen sich auf vorhandene Zielzeilen auswirken und welche wirklich neu sind. - Verwenden Sie eine zusätzliche Bedingung in der
WHEN MATCHEDKlausel, um festzustellen, ob die Zielzeile bereits von einem vorherigen Batch aktualisiert wurde. - Verwenden Sie eine zusätzliche Bedingung in der
WHEN MATCHEDKlausel undSETLogik, um zu überprüfen, ob dieselbe Zeile nicht zweimal aktualisiert werden kann.
- Verwenden Sie die
Da die TOP Klausel erst angewendet wird, nachdem diese Klauseln angewendet wurden, fügt jede Ausführung entweder eine wirklich nicht übereinstimmende Zeile ein oder aktualisiert eine vorhandene Zeile.
Bewährte Methoden zum Massenladen
Die MERGE Anweisung kann verwendet werden, um Daten aus einer Quelldatendatei effizient in eine Zieltabelle zu laden, indem die OPENROWSET(BULK...) Klausel als Tabellenquelle angegeben wird. Dadurch wird die gesamte Datei als einzelner Batch verarbeitet.
Zur Leistungsverbesserung des Massenladevorgangs werden die folgenden Richtlinien empfohlen:
Erstellen Sie für die Joinspalten in der Zieltabelle einen gruppierten Index.
Deaktivieren Sie andere nicht eindeutige, nicht gruppierte Indizes in der Zieltabelle während des Massenladevorgangs
MERGE, und aktivieren Sie sie danach. Dies ist üblich und nützlich für nächtliche Massendatenvorgänge.Verwenden Sie die
ORDERHinweiseUNIQUEin derOPENROWSET(BULK...)Klausel, um anzugeben, wie die Quelldatendatei sortiert wird.Standardmäßig geht der Massenvorgang davon aus, dass die Datendatei nicht sortiert ist. Daher ist es wichtig, dass die Quelldaten gemäß dem gruppierten Index in der Zieltabelle sortiert werden und dass der
ORDERHinweis verwendet wird, um die Reihenfolge anzugeben, damit der Abfrageoptimierer einen effizienteren Abfrageplan generieren kann. Hinweise werden zur Laufzeit validiert. Wenn der Datenstrom mit den angegebenen Hinweisen nicht übereinstimmt, wird ein Fehler ausgelöst.
Mit diesen Richtlinien wird sichergestellt, dass die Joinschlüssel eindeutig sind und die Sortierreihenfolge der Daten in der Quelldatei mit der Zieltabelle übereinstimmt. Die Abfrageleistung wird verbessert, da zusätzliche Sortiervorgänge nicht erforderlich sind und keine nicht benötigten Datenkopien angefordert werden.
Messen und Diagnostizieren der MERGE-Leistung
Die folgenden Features stehen Ihnen bei der Messung und Diagnose der Leistung von MERGE Aussagen zur Verfügung.
- Verwenden Sie den Zusammenführungs-Stmt-Zähler in der sys.dm_exec_query_optimizer_info dynamischen Verwaltungsansicht, um die Anzahl der Abfrageoptimierungen zurückzugeben, die für
MERGEAnweisungen gelten. - Verwenden Sie das
merge_action_typeAttribut in der sys.dm_exec_plan_attributes dynamischen Verwaltungsansicht, um den Typ des Triggerausführungsplans zurückzugeben, der als Ergebnis einerMERGEAnweisung verwendet wird. - Verwenden Sie eine Erweiterte Ereignissitzung, um Problembehandlungsdaten für die
MERGEAnweisung auf die gleiche Weise wie für andere DML-Anweisungen (Data Manipulation Language) zu sammeln. Weitere Informationen zur Übersicht über erweiterte Ereignisse finden Sie unter Schnellstart: Erweiterte Ereignisse und Verwenden des SSMS XEvent Profiler.
Examples
A. Verwenden von MERGE zum Ausführen von INSERT- und UPDATE-Vorgängen für eine Tabelle in einer einzelnen Anweisung
Ein häufiges Szenario ist die Aktualisierung einer oder mehrerer Spalten in einer Tabelle, wenn eine übereinstimmende Zeile vorhanden ist. Anderenfalls, wenn keine übereinstimmende Zeile vorhanden ist, das Einfügen der Daten als neue Zeile. Sie führen in der Regel ein Szenario aus, indem Sie Parameter an eine gespeicherte Prozedur übergeben, die die entsprechenden UPDATE und INSERT Anweisungen enthält. Mit der MERGE Anweisung können Sie beide Aufgaben in einer einzelnen Anweisung ausführen. Das folgende Beispiel zeigt eine gespeicherte Prozedur in der AdventureWorks2025-Datenbank, die sowohl eine Anweisung als auch eine INSERT Anweisung UPDATE enthält. Die Prozedur wird dann geändert, um die entsprechenden Vorgänge mithilfe einer einzelnen MERGE Anweisung auszuführen.
CREATE PROCEDURE dbo.InsertUnitMeasure @UnitMeasureCode NCHAR(3), @Name NVARCHAR(25)
AS
BEGIN
SET NOCOUNT ON;
-- Update the row if it exists.
UPDATE Production.UnitMeasure
SET Name = @Name
WHERE UnitMeasureCode = @UnitMeasureCode
-- Insert the row if the UPDATE statement failed.
IF (@@ROWCOUNT = 0)
BEGIN
INSERT INTO Production.UnitMeasure (
UnitMeasureCode,
Name
)
VALUES (@UnitMeasureCode, @Name)
END
END;
GO
-- Test the procedure and return the results.
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'Test Value';
SELECT UnitMeasureCode, Name
FROM Production.UnitMeasure
WHERE UnitMeasureCode = 'ABC';
GO
-- Rewrite the procedure to perform the same operations using the
-- MERGE statement.
-- Create a temporary table to hold the updated or inserted values
-- from the OUTPUT clause.
CREATE TABLE #MyTempTable (
ExistingCode NCHAR(3),
ExistingName NVARCHAR(50),
ExistingDate DATETIME,
ActionTaken NVARCHAR(10),
NewCode NCHAR(3),
NewName NVARCHAR(50),
NewDate DATETIME
);
GO
ALTER PROCEDURE dbo.InsertUnitMeasure @UnitMeasureCode NCHAR(3),
@Name NVARCHAR(25)
AS
BEGIN
SET NOCOUNT ON;
MERGE Production.UnitMeasure AS tgt
USING (SELECT @UnitMeasureCode, @Name) AS src(UnitMeasureCode, Name)
ON (tgt.UnitMeasureCode = src.UnitMeasureCode)
WHEN MATCHED
THEN
UPDATE
SET Name = src.Name
WHEN NOT MATCHED
THEN
INSERT (UnitMeasureCode, Name)
VALUES (src.UnitMeasureCode, src.Name)
OUTPUT deleted.*,
$action,
inserted.*
INTO #MyTempTable;
END;
GO
-- Test the procedure and return the results.
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'New Test Value';
EXEC InsertUnitMeasure @UnitMeasureCode = 'XYZ', @Name = 'Test Value';
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'Another Test Value';
SELECT * FROM #MyTempTable;
-- Cleanup
DELETE FROM Production.UnitMeasure
WHERE UnitMeasureCode IN ('ABC', 'XYZ');
DROP TABLE #MyTempTable;
GO
CREATE PROCEDURE dbo.InsertUnitMeasure @UnitMeasureCode NCHAR(3),
@Name NVARCHAR(25)
AS
BEGIN
SET NOCOUNT ON;
-- Update the row if it exists.
UPDATE Production.UnitMeasure
SET Name = @Name
WHERE UnitMeasureCode = @UnitMeasureCode
-- Insert the row if the UPDATE statement failed.
IF (@@ROWCOUNT = 0)
BEGIN
INSERT INTO Production.UnitMeasure (
UnitMeasureCode,
Name
)
VALUES (@UnitMeasureCode, @Name)
END
END;
GO
-- Test the procedure and return the results.
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'Test Value';
SELECT UnitMeasureCode, Name
FROM Production.UnitMeasure
WHERE UnitMeasureCode = 'ABC';
GO
-- Rewrite the procedure to perform the same operations using the
-- MERGE statement.
ALTER PROCEDURE dbo.InsertUnitMeasure @UnitMeasureCode NCHAR(3),
@Name NVARCHAR(25)
AS
BEGIN
SET NOCOUNT ON;
MERGE Production.UnitMeasure AS tgt
USING (
SELECT @UnitMeasureCode,
@Name
) AS src(UnitMeasureCode, Name)
ON (tgt.UnitMeasureCode = src.UnitMeasureCode)
WHEN MATCHED
THEN
UPDATE SET Name = src.Name
WHEN NOT MATCHED
THEN
INSERT (UnitMeasureCode, Name)
VALUES (src.UnitMeasureCode, src.Name);
END;
GO
-- Test the procedure and return the results.
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'New Test Value';
EXEC InsertUnitMeasure @UnitMeasureCode = 'XYZ', @Name = 'Test Value';
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'Another Test Value';
-- Cleanup
DELETE FROM Production.UnitMeasure
WHERE UnitMeasureCode IN ('ABC', 'XYZ');
GO
B. Verwenden von MERGE zum Ausführen von UPDATE- und DELETE-Operationen für eine Tabelle in einer einzelnen Anweisung
Das folgende Beispiel wird verwendet MERGE , um die ProductInventory Tabelle in der AdventureWorks2025-Beispieldatenbank täglich zu aktualisieren, basierend auf in der SalesOrderDetail Tabelle verarbeiteten Bestellungen. Die Quantity-Spalte der ProductInventory-Tabelle wird aktualisiert, indem die Anzahl der täglich aufgegebenen Bestellungen für die einzelnen Produkte in der SalesOrderDetail-Tabelle subtrahiert wird. Wenn die Anzahl der Bestellungen für ein Produkt dazu führt, dass der Produktbestand auf oder unter 0 (null) fällt, wird die Zeile für dieses Produkt aus der ProductInventory-Tabelle gelöscht.
CREATE PROCEDURE Production.usp_UpdateInventory @OrderDate DATETIME
AS
MERGE Production.ProductInventory AS tgt
USING (
SELECT ProductID,
SUM(OrderQty)
FROM Sales.SalesOrderDetail AS sod
INNER JOIN Sales.SalesOrderHeader AS soh
ON sod.SalesOrderID = soh.SalesOrderID
AND soh.OrderDate = @OrderDate
GROUP BY ProductID
) AS src(ProductID, OrderQty)
ON (tgt.ProductID = src.ProductID)
WHEN MATCHED
AND tgt.Quantity - src.OrderQty <= 0
THEN
DELETE
WHEN MATCHED
THEN
UPDATE
SET tgt.Quantity = tgt.Quantity - src.OrderQty,
tgt.ModifiedDate = GETDATE()
OUTPUT $action,
Inserted.ProductID,
Inserted.Quantity,
Inserted.ModifiedDate,
Deleted.ProductID,
Deleted.Quantity,
Deleted.ModifiedDate;
GO
EXECUTE Production.usp_UpdateInventory '20030501';
CREATE PROCEDURE Production.usp_UpdateInventory @OrderDate DATETIME
AS
MERGE Production.ProductInventory AS tgt
USING (
SELECT ProductID,
SUM(OrderQty)
FROM Sales.SalesOrderDetail AS sod
INNER JOIN Sales.SalesOrderHeader AS soh
ON sod.SalesOrderID = soh.SalesOrderID
AND soh.OrderDate = @OrderDate
GROUP BY ProductID
) AS src(ProductID, OrderQty)
ON (tgt.ProductID = src.ProductID)
WHEN MATCHED
AND tgt.Quantity - src.OrderQty <= 0
THEN
DELETE
WHEN MATCHED
THEN
UPDATE
SET tgt.Quantity = tgt.Quantity - src.OrderQty,
tgt.ModifiedDate = GETDATE();
GO
EXECUTE Production.usp_UpdateInventory '20030501';
C. Verwenden von MERGE zum Ausführen von UPDATE- und INSERT-Vorgängen für eine Zieltabelle unter Verwendung einer abgeleiteten Quelltabelle
Das folgende Beispiel verwendet, MERGE um die SalesReason Tabelle in der AdventureWorks2025-Datenbank entweder durch Aktualisierung oder Einfügen von Zeilen zu modifizieren.
Wenn der Wert von NewName in der Quelltabelle einem Wert in der Name-Spalte der Zieltabelle entspricht (SalesReason), wird die ReasonType-Spalte in der Zieltabelle aktualisiert. Wenn der Wert von NewName jedoch nicht übereinstimmt, wird die Quellzeile in die Zieltabelle eingefügt. Die Quelltabelle ist eine abgeleitete Tabelle, die mithilfe des Transact-SQL-Tabellenwertkonstruktors mehrere Zeilen für die Quelltabelle angibt. Weitere Informationen zum Verwenden des Tabellenwertkonstruktors in einer abgeleiteten Tabelle finden Sie unter Tabellenwertkonstruktor (Transact-SQL).
Die OUTPUT Klausel kann nützlich sein, um das Ergebnis von MERGE Anweisungen abzufragen, weitere Informationen finden Sie unter OUTPUT-Klausel (Transact-SQL). Das Beispiel zeigt auch, wie die Ergebnisse der OUTPUT Klausel in einer Tabellenvariablen gespeichert werden. Anschließend fassen Sie die Ergebnisse der MERGE Anweisung zusammen, indem Sie einen einfachen Auswahlvorgang ausführen, der die Anzahl der eingefügten und aktualisierten Zeilen zurückgibt.
-- Create a temporary table variable to hold the output actions.
DECLARE @SummaryOfChanges TABLE (Change VARCHAR(20));
MERGE INTO Sales.SalesReason AS tgt
USING (
VALUES ('Recommendation', 'Other'),
('Review', 'Marketing'),
('Internet', 'Promotion')
) AS src(NewName, NewReasonType)
ON tgt.Name = src.NewName
WHEN MATCHED
THEN
UPDATE
SET ReasonType = src.NewReasonType
WHEN NOT MATCHED BY TARGET
THEN
INSERT (Name, ReasonType)
VALUES (NewName, NewReasonType)
OUTPUT $action
INTO @SummaryOfChanges;
-- Query the results of the table variable.
SELECT Change,
COUNT(*) AS CountPerChange
FROM @SummaryOfChanges
GROUP BY Change;
Wenn der Wert von NewName in der Quelltabelle einem Wert in der Name-Spalte der Zieltabelle entspricht (SalesReason), wird die ReasonType-Spalte in der Zieltabelle aktualisiert. Wenn der Wert von NewName jedoch nicht übereinstimmt, wird die Quellzeile in die Zieltabelle eingefügt. Die Quelltabelle ist eine abgeleitete Tabelle, die mit SELECT ... UNION ALL mehrere Zeilen für die Quelltabelle angibt.
MERGE INTO Sales.SalesReason AS tgt
USING (
SELECT 'Recommendation', 'Other'
UNION ALL
SELECT 'Review', 'Marketing'
UNION ALL
SELECT 'Internet', 'Promotion'
) AS src(NewName, NewReasonType)
ON tgt.Name = src.NewName
WHEN MATCHED
THEN
UPDATE SET ReasonType = src.NewReasonType
WHEN NOT MATCHED BY TARGET
THEN
INSERT (Name, ReasonType)
VALUES (NewName, NewReasonType);
D. Einfügen der Ergebnisse der MERGE-Anweisung in eine andere Tabelle
Im folgenden Beispiel werden daten erfasst, die aus der OUTPUT Klausel einer MERGE Anweisung zurückgegeben werden, und fügt diese Daten in eine andere Tabelle ein. Die Anweisung MERGE aktualisiert die Quantity Spalte der ProductInventory Tabelle in der AdventureWorks2025-Datenbank, basierend auf den in der Tabelle SalesOrderDetail verarbeiteten Aufträgen. In diesem Beispiel werden die aktualisierten Zeilen erfasst und in eine andere Tabelle eingefügt, in der Bestandsänderungen nachverfolgt werden.
CREATE TABLE Production.UpdatedInventory (
ProductID INT NOT NULL,
LocationID INT,
NewQty INT,
PreviousQty INT,
CONSTRAINT PK_Inventory PRIMARY KEY CLUSTERED (
ProductID,
LocationID
)
);
GO
INSERT INTO Production.UpdatedInventory
SELECT ProductID, LocationID, NewQty, PreviousQty
FROM (
MERGE Production.ProductInventory AS pi
USING (
SELECT ProductID, SUM(OrderQty)
FROM Sales.SalesOrderDetail AS sod
INNER JOIN Sales.SalesOrderHeader AS soh
ON sod.SalesOrderID = soh.SalesOrderID
AND soh.OrderDate BETWEEN '20030701'
AND '20030731'
GROUP BY ProductID
) AS src(ProductID, OrderQty)
ON pi.ProductID = src.ProductID
WHEN MATCHED
AND pi.Quantity - src.OrderQty >= 0
THEN
UPDATE SET pi.Quantity = pi.Quantity - src.OrderQty
WHEN MATCHED
AND pi.Quantity - src.OrderQty <= 0
THEN
DELETE
OUTPUT $action,
Inserted.ProductID,
Inserted.LocationID,
Inserted.Quantity AS NewQty,
Deleted.Quantity AS PreviousQty
) AS Changes(Action, ProductID, LocationID, NewQty, PreviousQty)
WHERE Action = 'UPDATE';
GO
E. Verwenden von MERGE zum Ausführen von INSERT oder UPDATE auf eine Edge-Zieltabelle in einer Graphdatenbank
In diesem Beispiel erstellen Sie Knotentabellen Person und City und eine Edgetabelle livesIn. Sie verwenden die MERGE Anweisung am livesIn Rand und fügen eine neue Zeile ein, wenn der Rand nicht bereits zwischen einem und Persondem City . Wenn der Edge bereits vorhanden ist, aktualisieren Sie nur das StreetAddress-Attribut auf dem livesIn-Edge.
-- CREATE node and edge tables
CREATE TABLE Person
(
ID INTEGER PRIMARY KEY,
PersonName VARCHAR(100)
)
AS NODE
GO
CREATE TABLE City
(
ID INTEGER PRIMARY KEY,
CityName VARCHAR(100),
StateName VARCHAR(100)
)
AS NODE
GO
CREATE TABLE livesIn
(
StreetAddress VARCHAR(100)
)
AS EDGE
GO
-- INSERT some test data into node and edge tables
INSERT INTO Person VALUES (1, 'Ron'), (2, 'David'), (3, 'Nancy')
GO
INSERT INTO City VALUES (1, 'Redmond', 'Washington'), (2, 'Seattle', 'Washington')
GO
INSERT livesIn SELECT P.$node_id, C.$node_id, c
FROM Person P, City C, (values (1,1, '123 Avenue'), (2,2,'Main Street')) v(a,b,c)
WHERE P.id = a AND C.id = b
GO
-- Use MERGE to update/insert edge data
CREATE OR ALTER PROCEDURE mergeEdge
@PersonId integer,
@CityId integer,
@StreetAddress varchar(100)
AS
BEGIN
MERGE livesIn
USING ((SELECT @PersonId, @CityId, @StreetAddress) AS T (PersonId, CityId, StreetAddress)
JOIN Person ON T.PersonId = Person.ID
JOIN City ON T.CityId = City.ID)
ON MATCH (Person-(livesIn)->City)
WHEN MATCHED THEN
UPDATE SET StreetAddress = @StreetAddress
WHEN NOT MATCHED THEN
INSERT ($from_id, $to_id, StreetAddress)
VALUES (Person.$node_id, City.$node_id, @StreetAddress) ;
END
GO
-- Following will insert a new edge in the livesIn edge table
EXEC mergeEdge 3, 2, '4444th Avenue'
GO
-- Following will update the StreetAddress on the edge that connects Ron to Redmond
EXEC mergeEdge 1, 1, '321 Avenue'
GO
-- Verify that all the address were added/updated correctly
SELECT PersonName, CityName, StreetAddress
FROM Person , City , livesIn
WHERE MATCH(Person-(livesIn)->city)
GO