Snowpark Migration Accelerator: Zusammenführung

Beschreibung

Die MERGE-Anweisung kombiniert Daten aus einer oder mehreren Quelltabellen mit einer Zieltabelle, so dass Sie Aktualisierungen und Einfügungen in einem einzigen Vorgang durchführen können. Anhand der von Ihnen definierten Bedingungen bestimmt es, ob bestehende Zeilen aktualisiert oder neue Zeilen in die Zieltabelle eingefügt werden sollen. Dies ist effizienter als die Verwendung separater INSERT, UPDATE und DELETE- Anweisungen. Die MERGE-Anweisung liefert immer konsistente Ergebnisse, wenn sie mehrmals mit denselben Daten ausgeführt wird.

In Spark finden Sie die MERGE-Syntax in der Spark-Dokumentation.

MERGE INTO target_table_name [target_alias]
   USING source_table_reference [source_alias]
   ON merge_condition
   { WHEN MATCHED [ AND matched_condition ] THEN matched_action |
     WHEN NOT MATCHED [BY TARGET] [ AND not_matched_condition ] THEN not_matched_action |
     WHEN NOT MATCHED BY SOURCE [ AND not_matched_by_source_condition ] THEN not_matched_by_source_action } [...]

matched_action
 { DELETE |
   UPDATE SET * |
   UPDATE SET { column = { expr | DEFAULT } } [, ...] }

not_matched_action
 { INSERT * |
   INSERT (column1 [, ...] ) VALUES ( expr | DEFAULT ] [, ...] )

not_matched_by_source_action
 { DELETE |
   UPDATE SET { column = { expr | DEFAULT } } [, ...] }
Copy

In Snowflake folgt die MERGE-Anweisung dieser Syntax (Weitere Einzelheiten finden Sie in der Snowflake-Dokumentation):

MERGE INTO <target_table> USING <source> ON <join_expr> { matchedClause | notMatchedClause } [ ... ]

matchedClause ::=
  WHEN MATCHED [ AND <case_predicate> ] THEN { UPDATE SET <col_name> = <expr> [ , <col_name2> = <expr2> ... ] | DELETE } [ ... ]
  
notMatchedClause ::=
   WHEN NOT MATCHED [ AND <case_predicate> ] THEN INSERT [ ( <col_name> [ , ... ] ) ] VALUES ( <expr> [ , ... ] )
Copy

Der entscheidende Unterschied besteht darin, dass Snowflake keine direkte Entsprechung zur WHEN NOT MATCHED BY SOURCE-Klausel hat. Um eine ähnliche Funktionalität in Snowflake zu erreichen, ist eine Problemumgehung erforderlich.

Beispielhafte Quellcode-Muster

Beispielhafte Hilfsdaten

Bemerkung

Die folgenden Codebeispiele wurden ausgeführt, damit Sie besser verstehen, wie sie funktionieren:

CREATE OR REPLACE people_source ( 
  person_id  INTEGER NOT NULL PRIMARY KEY, 
  first_name STRING NOT NULL, 
  last_name  STRING NOT NULL, 
  title      STRING NOT NULL,
);

CREATE OR REPLACE TABLE people_target ( 
  person_id  INTEGER NOT NULL PRIMARY KEY, 
  first_name STRING NOT NULL, 
  last_name  STRING NOT NULL, 
  title      STRING NOT NULL DEFAULT 'NONE'
);


INSERT INTO people_target VALUES (1, 'John', 'Smith', 'Mr');
INSERT INTO people_target VALUES (2, 'alice', 'jones', 'Mrs');
INSERT INTO people_source VALUES (2, 'Alice', 'Jones', 'Mrs.');
INSERT INTO people_source VALUES (3, 'Jane', 'Doe', 'Miss');
INSERT INTO people_source VALUES (4, 'Dave', 'Brown', 'Mr');
Copy
CREATE OR REPLACE TABLE people_source (
    person_id  INTEGER NOT NULL PRIMARY KEY,
    first_name VARCHAR(20) NOT NULL,
    last_name VARCHAR(20) NOT NULL,
    title VARCHAR(10) NOT NULL
);

CREATE OR REPLACE TABLE people_target (
    person_id  INTEGER NOT NULL PRIMARY KEY,
    first_name VARCHAR(20) NOT NULL,
    last_name VARCHAR(20) NOT NULL,
    title VARCHAR(10) NOT NULL DEFAULT 'NONE'
);


INSERT INTO people_target VALUES (1, 'John', 'Smith', 'Mr');
INSERT INTO people_target VALUES (2, 'alice', 'jones', 'Mrs');
INSERT INTO people_source VALUES (2, 'Alice', 'Jones', 'Mrs.');
INSERT INTO people_source VALUES (3, 'Jane', 'Doe', 'Miss');
INSERT INTO people_source VALUES (4, 'Dave', 'Brown', 'Mr');
Copy

MERGE-Anweisung - Fall einfügen und aktualisieren

Spark

MERGE INTO people_target pt 
USING people_source ps 
ON    (pt.person_id = ps.person_id) 
WHEN MATCHED THEN UPDATE 
  SET pt.first_name = ps.first_name, 
      pt.last_name = ps.last_name, 
      pt.title = DEFAULT 
WHEN NOT MATCHED THEN INSERT 
  (pt.person_id, pt.first_name, pt.last_name, pt.title) 
  VALUES (ps.person_id, ps.first_name, ps.last_name, ps.title);


SELECT * FROM people_target;
Copy
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
        1|John      |Smith    |Mr   |
        2|Alice     |Jones    |NONE |
        3|Jane      |Doe      |Miss |
        4|Dave      |Brown    |Mr   |
Copy

Snowflake

MERGE INTO people_target2 pt 
USING people_source ps 
ON    (pt.person_id = ps.person_id) 
WHEN MATCHED THEN UPDATE 
  SET pt.first_name = ps.first_name, 
      pt.last_name = ps.last_name, 
      pt.title = DEFAULT 
WHEN NOT MATCHED THEN INSERT 
  (pt.person_id, pt.first_name, pt.last_name, pt.title) 
  VALUES (ps.person_id, ps.first_name, ps.last_name, ps.title);


SELECT * FROM PUBLIC.people_target ORDER BY person_id;
Copy
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
        1|John      |Smith    |Mr   |
        2|Alice     |Jones    |NONE |
        3|Jane      |Doe      |Miss |
        4|Dave      |Brown    |Mr   |
Copy

Die INSERT und UPDATE-Operationen funktionieren in Snowflake auf die gleiche Weise. In beiden SQL-Dialekten können Sie DEFAULT als Ausdruck verwenden, um eine Spalte auf ihren Standardwert zu setzen.

Spark erlaubt Einfüge- und Aktualisierungsoperationen, ohne die Spalten explizit aufzulisten. Wenn keine Spalten angegeben sind, betrifft die Operation alle Spalten der Tabelle. Damit dies korrekt funktioniert, müssen die Quell- und die Zieltabelle identische Spaltenstrukturen haben. Wenn die Spaltenstrukturen nicht übereinstimmen, erhalten Sie einen Parsing-Fehler.

UPDATE SET *
-- This is equivalent to UPDATE SET col1 = source.col1 [, col2 = source.col2 ...]

INSERT * 
-- This command copies all columns from the source table to the target table, matching columns by name. It is the same as explicitly listing all columns in both the INSERT and VALUES clauses.

Since Snowflake doesn't support these options, the migration process will instead list all columns from the target table.

### MERGE Statement - Delete Case

 
```{code} sql
:force:
MERGE INTO people_target pt 
USING people_source ps 
ON    (pt.person_id = ps.person_id)
WHEN MATCHED AND pt.person_id < 3 THEN DELETE
WHEN NOT MATCHED BY TARGET THEN INSERT *;

SELECT * FROM people_target;
Copy
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
        1|John      |Smith    |Mr   |
        3|Jane      |Doe      |Miss |
        4|Dave      |Brown    |Mr   |
Copy

Snowflake

MERGE INTO people_target pt 
USING people_source ps 
ON    (pt.person_id = ps.person_id)
WHEN MATCHED AND pt.person_id < 3 THEN DELETE
WHEN NOT MATCHED THEN INSERT 
  (pt.person_id, pt.first_name, pt.last_name, pt.title) 
  VALUES (ps.person_id, ps.first_name, ps.last_name, ps.title);


SELECT * FROM people_target;
Copy
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
        1|John      |Smith    |Mr   |
        3|Jane      |Doe      |Miss |
        4|Dave      |Brown    |Mr   |
Copy

Die DELETE-Aktion funktioniert in Snowflake auf dieselbe Weise wie in anderen Datenbanken. Sie können auch zusätzliche Bedingungen zu den Klauseln MATCHED und NOT MATCHED hinzufügen.

WHEN NOT MATCHED BY TARGET und WHEN NOT MATCHED sind gleichwertige Klauseln, die austauschbar in SQL-Zusammenführungsanweisungen verwendet werden können.

MERGE-Anweisung - WHENNOTMATCHEDBYSOURCE

WHEN NOT MATCHED BY SOURCE-Klauseln werden ausgelöst, wenn eine Zeile in der Zieltabelle keine passenden Zeilen in der Quelltabelle hat. Dies geschieht, wenn sowohl die merge_condition als auch die optionale not_match_by_source_condition auf „true“ ausgewertet werden. Weitere Einzelheiten finden Sie in der Spark-Dokumentation.

Snowflake unterstützt diese Klausel nicht direkt. Um diese Beschränkung zu umgehen, können Sie die folgende Abhilfe sowohl für DELETE als auch für UPDATE-Aktionen verwenden.

MERGE INTO people_target pt 
USING people_source ps 
ON pt.person_id = ps.person_id
WHEN NOT MATCHED BY SOURCE THEN DELETE;


SELECT * FROM people_target;
Copy
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
        2|Alice     |Jones    |NONE |
Copy

Snowflake

MERGE INTO people_target pt 
USING (
    SELECT 
        pt.person_id 
    FROM
        people_target pt LEFT 
    JOIN people_source ps ON pt.person_id = ps.person_id
    WHERE 
        ps.person_id is null
) s_src
    ON s_src.person_id = pt.person_id
WHEN MATCHED THEN DELETE;

SELECT * FROM people_target;
Copy
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
        2|Alice     |Jones    |NONE |
Copy

Die DELETE-Aktion funktioniert in Snowflake auf dieselbe Weise wie in anderen Datenbanken. Sie können auch zusätzliche Bedingungen zu den Klauseln MATCHED und NOT MATCHED hinzufügen.

Bekannte Probleme

1. MERGE is very similar in both languages

Apache Spark bietet zwar zusätzliche Features, aber Sie können ähnliche Funktionen in Snowflake mit alternativen Ansätzen erreichen, wie in den vorherigen Beispielen gezeigt.