Snowpark Migration Accelerator: 병합

설명

MERGE 문은 1개 이상의 소스 테이블의 데이터를 대상 테이블과 결합하여 한 번의 작업으로 업데이트 및 삽입을 수행할 수 있습니다. 정의한 조건에 따라 기존 행을 업데이트할지, 아니면 대상 테이블에 새 행을 삽입할지 결정합니다. 이렇게 하면 INSERT, UPDATEDELETE 문을 따로 사용하는 것보다 효율적입니다. MERGE 문은 동일한 데이터로 여러 번 실행할 때 항상 일관된 결과를 생성합니다.

Spark의 MERGE 구문은 Spark 설명서 에서 찾을 수 있습니다.

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

Snowflake에서 MERGE 문은 이 구문을 따릅니다(자세한 내용은 Snowflake 설명서) 참조:

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

핵심적인 차이점은 Snowflake에는 WHEN NOT MATCHED BY SOURCE 절과 직접적으로 대응하는 절이 없다는 것입니다. Snowflake에서 유사한 기능을 구현하려면 해결 방법이 필요합니다.

샘플 소스 패턴

샘플 보조 데이터

참고

작동 방식을 더 잘 이해할 수 있도록 다음 코드 예제를 실행해 보았습니다.

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 문 - 케이스 삽입 및 업데이트

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

INSERTUPDATE 작업은 Snowflake에서 동일한 방식으로 작동합니다. SQL 언어 모두에서 DEFAULT 를 식으로 사용하여 열을 기본값으로 설정할 수 있습니다.

Spark에서는 열을 명시적으로 나열하지 않고도 삽입 및 업데이트 작업을 수행할 수 있습니다. 열을 지정하지 않으면 작업은 테이블의 모든 열에 영향을 줍니다. 이 기능이 올바르게 작동하려면 소스 테이블과 대상 테이블의 열 구조가 동일해야 합니다. 열 구조가 일치하지 않으면 구문 분석 오류가 발생합니다.

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

Snowflake의 DELETE 작업은 다른 데이터베이스에서와 동일한 방식으로 작동합니다. MATCHEDNOT MATCHED 절에 추가 조건을 추가할 수도 있습니다.

WHEN NOT MATCHED BY TARGETWHEN NOT MATCHED 는 SQL 병합 문에서 서로 바꿔서 사용할 수 있는 동등한 절입니다.

MERGE 문 - WHEN NOT MATCHED BY SOURCE

WHEN NOT MATCHED BY SOURCE 절은 대상 테이블의 행이 소스 테이블에 일치하는 행이 없을 때 트리거됩니다. 이는 merge_condition 및 선택 사항인 not_match_by_source_condition 이 모두 true로 평가될 때 발생합니다. 자세한 내용은 Spark 설명서 를 참조하십시오.

Snowflake는 이 절을 직접 지원하지 않습니다. 이 제한을 처리하려면 DELETEUPDATE 작업 모두에 대해 다음 해결 방법을 사용할 수 있습니다.

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

Snowflake의 DELETE 작업은 다른 데이터베이스에서와 동일한 방식으로 작동합니다. MATCHEDNOT MATCHED 절에 추가 조건을 추가할 수도 있습니다.

알려진 문제

1. MERGE is very similar in both languages

Apache Spark는 추가 기능을 제공하지만, 이전 예제에서 설명한 것처럼 다른 접근법을 사용하여 Snowflake에서 유사한 기능을 구현할 수 있습니다.