Freigeben über


MERGE (Transact-SQL)

Gilt für:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse Analytics (dedicated SQL pool only)SQL-Datenbank in Microsoft FabricLager 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 MERGE zum 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-Anweisung UPDATE FROM ... JOIN als Problemumgehung bis zur Version 10.0.17829.0.
  • Eine MERGE Aktualisierung wird als Lösch- und Einfügepaar implementiert. Die anzahl der betroffenen Zeilen für eine MERGE Aktualisierung umfasst die gelöschten und eingefügten Zeilen.
  • MERGE...WHEN NOT MATCHED INSERT wird für Tabellen mit IDENTITY Spalten nicht unterstützt.
  • Der Tabellenwertkonstruktor kann in der USING Klausel für die Quelltabelle nicht verwendet werden. Verwenden Sie SELECT ... 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 SEToder INSERT einem Vorgang innerhalb MERGE (nicht spezifisch für eine WHEN [NOT] MATCHED Klausel) angegeben.
  • Jede Spalte in der JOIN Bedingung weist einen nicht gruppierten Index (NCI) auf.
  • Zieltabelle wird HASH verteilt

Wenn dieser Fehler auftritt, wird folgende Problemumgehung vorgeschlagen:

  • Entfernen Sie den nicht gruppierten Index (NCI) aus den JOIN Spalten, oder verbinden Sie den Index auf Spalten ohne NCI. Wenn Sie die zugrunde liegenden Tabellen später so aktualisieren, dass sie eine NCI in die JOIN Spalten aufnehmen, ist Ihre MERGE Anweisung 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 MERGE Anweisungen. Wie bei allen UPDATEs finden Sie möglicherweise eine bessere Leistung mit Spaltenspeicherindizes, indem Sie eine mehrstufige Rowstore-Tabelle aktualisieren und dann einen Batch DELETE ausführen und INSERTanstelle 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, UPDATEund DELETE Logik besser funktionieren, mit weniger Blockierung als eine MERGE Anweisung.
  • 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 dies HOLDLOCK gegen Verstöße gegen eindeutige Schlüssel verstößt. HOLDLOCK ist ein Synonym für die SERIALIZABLE Transaktionsisolationsstufe, die es anderen gleichzeitigen Transaktionen nicht ermöglicht, Daten zu ändern, die diese Transaktion gelesen hat. SERIALIZABLE ist 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 Informationen HOLDLOCKfinden 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 WHEN Klausel 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 der ON Klausel 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 den WHEN Klauseln der MERGE Anweisung. Sie können beispielsweise die MERGE Anweisung 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 Abfragehinweis PARAMETERIZATION FORCED an. Weitere Informationen finden Sie unter Angeben des Abfrageparametrisierungsverhaltens mithilfe von Planhinweislisten.
  • Wenn MERGE Anweisungen häufig in der Datenbank ausgeführt werden, sollten Sie die PARAMETERIZATION Option für die Datenbank auf festlegen FORCED. Legen Sie diese Option mit Bedacht fest. Die PARAMETERIZATION-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 MERGE Anweisung 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 ON Klausel, um zu bestimmen, welche Quellzeilen sich auf vorhandene Zielzeilen auswirken und welche wirklich neu sind.
    • Verwenden Sie eine zusätzliche Bedingung in der WHEN MATCHED Klausel, um festzustellen, ob die Zielzeile bereits von einem vorherigen Batch aktualisiert wurde.
    • Verwenden Sie eine zusätzliche Bedingung in der WHEN MATCHED Klausel und SET Logik, um zu überprüfen, ob dieselbe Zeile nicht zweimal aktualisiert werden kann.

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 ORDER Hinweise UNIQUE in der OPENROWSET(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 ORDER Hinweis 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.

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