{#merge-merge} # MERGE 패턴이 이미 있으면 그것을 일치시키고 없으면 만들며, 어느 쪽이든 그 변수를 바인딩합니다. {#merge-synopsis} ## 개요
MERGE pattern
    [ ON { CREATE | MATCH } SET set_item [, set_item ] ... ] ...

굵게 키워드 · 기울임 직접 채우는 자리 · [ ] 생략 가능 · ... 반복 가능. 구문 표기 규약을 참고하십시오.

{#merge-description} ## 설명 `MERGE`는 [`MATCH`](match.md)와 [`CREATE`](create.md)의 일을 하나의 절이 하는 것입니다. 자기 패턴을 찾고, 그 패턴이 있으면 `MATCH`처럼 동작하고 없으면 `CREATE`처럼 동작합니다. 어느 쪽이든 패턴의 변수는 결국 바인딩되므로, 쿼리의 나머지는 둘 중 무엇이 일어났는지 알 필요가 없습니다. `MERGE`에 관한 모든 것을 규칙 하나가 결정합니다. 이 절은 **패턴 전체**를 봅니다: - 패턴 전체가 일치하면 아무것도 쓰이지 않습니다. - 그중 어느 부분이라도 없으면 **패턴 전체가 만들어집니다.** 그래프의 다른 곳에 이미 있는 부분까지 포함해서입니다. `a`와 `b`는 있고 간선만 없는 상태에서 `(a)-[:e]->(b)`를 merge하면, 간선과 함께 두 번째 `a`와 두 번째 `b`가 만들어집니다. - 그러므로 이미 무엇이 있는지 확실하지 않을 때는 **요소를 하나씩** merge하십시오. 정점마다 `MERGE`를 쓰고, 그다음 그것들이 바인딩한 변수 사이의 간선에 `MERGE`를 쓰십시오. 그렇게 쓰면 `MERGE`는 멱등합니다. 그 밖의 규칙입니다: - `MERGE`는 **패턴을 정확히 하나** 받습니다. 쉼표로 구분한 패턴은 구문 오류입니다. `MERGE` 절을 여러 개 쓰십시오. - `ON CREATE SET`은 패턴이 만들어졌을 때만, `ON MATCH SET`은 일치했을 때만 실행됩니다. 둘 다 어느 순서로든 줄 수 있고, 각각 [`SET`](set.md)의 항목 목록을 받습니다. - 패턴 안의 속성도 일치 대상의 일부입니다. `MERGE (m:movie {title: 'Tenet'})`는 `title`이 정확히 `Tenet`인 `movie`에만 일치하며, `title`을 갖고 있기만 한 것에는 일치하지 않습니다. - `MERGE`는 들어오는 행마다 한 번 실행됩니다. 쿼리를 시작하거나, 다른 절 뒤에 오거나, 쿼리를 끝낼 수 있습니다. {#merge-parameters} ## 매개변수 pattern : [`MATCH`](match.md) 구문의 경로 패턴 하나입니다. 그 안의 모든 속성은 일치 조건이면서, 만들 때는 설정할 속성이기도 합니다. ON CREATE SET : 패턴이 만들어졌을 때만 적용되는 할당입니다. ON MATCH SET : 패턴을 찾았을 때만 적용되는 할당입니다. set_item : [`SET`](set.md) 구문의 할당입니다. `variable.property = expression`, `variable = map`, `variable += map` 중 하나입니다. {#merge-examples} ## 예제 모든 예제는 [예제 데이터셋](../../get_started/example-dataset.md)에서 실행됩니다. The last example undoes them. {#merge-create-the-vertex-or-find-it} ### 정점을 만들거나 찾기 첫 실행은 만듭니다: ```cypher MERGE (m:movie {title: 'Tenet'}) RETURN m.title AS film, m.year AS year; ``` ``` film | year ---------+------ "Tenet" | (1 row) ``` 패턴에 `title`만 있었으므로 `year`는 설정되지 않았습니다. 두 번째 실행은 같은 정점을 찾고 아무것도 쓰지 않습니다: ```cypher MERGE (m:movie {title: 'Tenet'}) RETURN m.title AS film, m.year AS year; ``` ``` film | year ---------+------ "Tenet" | (1 row) ``` ```cypher MATCH (m:movie {title: 'Tenet'}) RETURN count(*) AS rows; ``` ``` rows ------ 1 (1 row) ``` {#merge-set-different-properties-on-create-and-on-match} ### 만들 때와 일치할 때 서로 다른 속성 설정하기 아무것도 없는 상태에서 시작합니다: ```cypher MATCH (m:movie {title: 'Tenet'}) DETACH DELETE m; ``` ``` UPDATE 1 ``` ```cypher MERGE (m:movie {title: 'Tenet'}) ON CREATE SET m.year = 2020, m.source = 'created' ON MATCH SET m.source = 'matched' RETURN m.title AS film, m.year AS year, m.source AS source; ``` ``` film | year | source ---------+------+----------- "Tenet" | 2020 | "created" (1 row) ``` 똑같은 문장을 두 번째로 실행하면 다른 분기를 탑니다: ```cypher MERGE (m:movie {title: 'Tenet'}) ON CREATE SET m.year = 2020, m.source = 'created' ON MATCH SET m.source = 'matched' RETURN m.title AS film, m.year AS year, m.source AS source; ``` ``` film | year | source ---------+------+----------- "Tenet" | 2020 | "matched" (1 row) ``` `year`는 만들기 분기가 준 값을 그대로 유지합니다. `ON MATCH SET`이 그것에 손대지 않았기 때문입니다. {#merge-see-a-whole-pattern-merge-duplicate-a-vertex} ### 패턴 전체를 MERGE하면 정점이 중복되는 것 보기 Christopher Nolan은 한 명이고, 그는 `Tenet`을 연출하지 않았습니다: ```cypher MATCH (m:movie {title: 'Tenet'}) DETACH DELETE m; MATCH (p:person {name: 'Christopher Nolan'}) RETURN count(*) AS nolans; ``` ``` UPDATE 1 nolans -------- 1 (1 row) ``` 경로 전체를 merge하면 간선이 없으므로 일치하는 것을 찾지 못합니다. 그래서 경로 전체를 만듭니다: ```cypher MERGE (d:person {name: 'Christopher Nolan'})-[:directed]->(m:movie {title: 'Tenet'}) RETURN d.name AS director, m.title AS film; ``` ``` director | film ---------------------+--------- "Christopher Nolan" | "Tenet" (1 row) ``` ```cypher MATCH (p:person {name: 'Christopher Nolan'}) RETURN count(*) AS nolans; ``` ``` nolans -------- 2 (1 row) ``` `born` 속성도 없고 원본의 간선도 하나 없는 두 번째 Christopher Nolan입니다. `MERGE`가 불러들이는 실수가 이것입니다. {#merge-merge-one-element-at-a-time-instead} ### 대신 요소를 하나씩 merge하기 그것을 되돌리고, 그다음 요소를 하나씩 따로 merge합니다: ```cypher MATCH (p:person {name: 'Christopher Nolan'}) WHERE NOT EXISTS { MATCH (p)-[:directed]->(:movie {title: 'Inception'}) } DETACH DELETE p; MATCH (m:movie {title: 'Tenet'}) DETACH DELETE m; ``` ``` UPDATE 2 UPDATE 1 ``` ```cypher MERGE (d:person {name: 'Christopher Nolan'}) MERGE (m:movie {title: 'Tenet'}) MERGE (d)-[:directed]->(m) RETURN d.name AS director, m.title AS film; ``` ``` director | film ---------------------+--------- "Christopher Nolan" | "Tenet" (1 row) ``` ```cypher MATCH (p:person {name: 'Christopher Nolan'}) RETURN count(*) AS nolans; ``` ``` nolans -------- 1 (1 row) ``` 첫 `MERGE`는 이미 있는 사람을 일치시켰고, 둘째는 영화를 만들었고, 셋째는 간선만 만들었습니다. 같은 세 절을 다시 실행해도 아무것도 바뀌지 않습니다: ```cypher MATCH (p:person {name: 'Christopher Nolan'})-[:directed]->(m:movie) RETURN count(*) AS edges; ``` ``` edges ------- 3 (1 row) ``` 원래 데이터셋의 둘에 merge한 하나를 더한 것이며, 그 문장을 몇 번 실행하든 그대로입니다. {#merge-reject-more-than-one-pattern} ### 패턴이 둘 이상이면 거부된다 ```cypher MERGE (a:movie {title: 'A'}), (b:movie {title: 'B'}); ``` ``` ERROR: syntax error at or near "," LINE 1: MERGE (a:movie {title: 'A'}), (b:movie {title: 'B'}); ^ ``` `MERGE` 절을 두 개 쓰십시오. {#merge-undo-the-examples} ### 예제 되돌리기 ```cypher MATCH (m:movie {title: 'Tenet'}) DETACH DELETE m; ``` ``` UPDATE 2 ``` {#merge-notes} ## 참고 고유성 제약은 중복 위험을 조용한 데이터 오염이 아니라 깔끔한 실패로 바꿔 줍니다. `person`의 `name`에 고유성이 걸려 있으면, 위의 패턴 전체 merge는 두 번째 Nolan을 만들 수 없습니다: ```cypher CREATE CONSTRAINT unique_person_name ON person ASSERT name IS UNIQUE; MERGE (d:person {name: 'Christopher Nolan'})-[:directed]->(m:movie {title: 'Tenet'}) RETURN d.name AS director, m.title AS film; ``` ``` CREATE CONSTRAINT ERROR: conflicting key value violates exclusion constraint "unique_person_name" DETAIL: Key ((properties.'name'))=("Christopher Nolan") conflicts with existing key ((properties.'name'))=("Christopher Nolan"). ``` 아무것도 만들어지지 않고, 트랜잭션이 그 이유를 보고합니다. merge에 쓰는 키가 무엇이든 그 키에 제약을 선언하십시오. {#merge-compatibility} ## 호환성 {#merge-merge-is-not-a-gql-clause} ### MERGE는 GQL 절이 아니다 ISO/IEC 39075에는 `MERGE`가 없습니다. 표준의 데이터 변경 문장은 ``(§13.2), ``(§13.3), ``(§13.4), ``(§13.5)입니다. `MERGE`는 Cypher에서 왔고 AgensGraph는 그것을 유지합니다. 표준만으로 같은 일을 하려면 [`CALL { subquery }`](call-subquery.md)를 쓰거나, `EXISTS` 검사 뒤에 [`INSERT`](insert.md)를 쓰십시오. {#merge-see-also} ## 관련 항목 - [`CREATE`](create.md) — 조건 없이 쓰기 - [`MATCH`](match.md) — 패턴 구문 - [`SET`](set.md) — `ON CREATE SET`과 `ON MATCH SET`이 받는 할당 구문 - [`DELETE`](delete.md) — merge가 만든 것을 지우기