{#with-with} # WITH 작업 행을 새 컬럼 집합으로 투영해 다음 절에 넘깁니다. 파이프라인 가운데에 있는 `RETURN`입니다. {#with-synopsis} ## 개요
WITH [ DISTINCT | ALL ] { * | expression [ AS alias ] } [, ...] [ WHERE condition ]

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

{#with-description} ## 설명 `WITH`는 파이프라인의 한 구역을 닫고 다음 구역을 엽니다. [`RETURN`](return.md)과 정확히 같은 방식으로 행마다 표현식을 평가하고, 그 결과 컬럼을 뒤따르는 절에 넘깁니다. 세 가지 일에 이것이 필요합니다: - **집계한 다음 걸러 내거나 더 일치시키기.** 집계 함수는 `WHERE`에 올 수 없으므로, `WITH`에서 집계하고 그 출력을 걸러 내십시오. - **값을 한 번만 계산해** 뒤따르는 여러 절에서 쓰기. - 쿼리의 비싼 부분이 실행되기 전에 `DISTINCT`·`ORDER BY`·`LIMIT`으로 **파이프라인을 줄이기.** 이것이 투영이라는 점에서 따라오는 규칙들입니다: - `WITH`는 유효 범위를 **교체합니다.** 투영한 것만 살아남습니다. 빼놓은 변수는 사라지고, 그것을 뒤에서 언급하면 `variable does not exist`가 나옵니다. 버리지 않고 더하려면 `WITH *, expr AS v`로 쓰거나 [`LET`](let.md)을 쓰십시오. - 각 출력 이름은 **그 절 안에서 고유**해야 합니다. 같은 이름을 두 번 투영하면 `WITH passes on "..." more than once`가 나옵니다. `RETURN`에는 그런 규칙이 없습니다. - 이 절의 `WHERE`는 투영과 집계가 끝난 **뒤에** 실행되므로, 집계의 별칭을 검사할 수 있습니다. - `ORDER BY`, `SKIP`/`OFFSET`, `LIMIT`은 `WITH` 뒤에 오는 별개의 절이고, 따라서 그 `WHERE` 뒤에도 옵니다. 필터가 먼저 실행되고, 페이지 나누기는 살아남은 것에 적용됩니다. - `WITH`는 쿼리를 **시작**할 수도, 끝낼 수도 없습니다. 문장 맨 앞의 `WITH`는 SQL의 공통 테이블 표현식이고, 그것은 이름과 괄호로 감싼 쿼리를 받는 다른 절입니다. [`LET`](let.md)에는 그런 충돌이 없어서 쿼리를 시작할 수 있습니다. {#with-parameters} ## 매개변수 DISTINCT : 투영한 행을 넘기기 전에 중복 행을 없앱니다. ALL : 중복 행을 그대로 둡니다. 기본값입니다. \* : 유효 범위의 이름 있는 모든 바인딩을 그대로 통과시킵니다. `WITH *, expr AS v`처럼 다른 항목과 함께 쓰면 어떤 컬럼도 버리지 않고 컬럼을 더할 수 있습니다. expression : 유효 범위의 바인딩에 대한 Cypher 표현식이면 무엇이든 되고, 집계 함수도 됩니다. alias : 다음 절이 쓰는 이름입니다. 변수 참조만 있는 것이 아니라면 필수입니다. 뒤따르는 절이 그것을 이름으로 부를 수 있어야 하기 때문입니다. condition : 투영된 행을 걸러 내는 불리언 표현식입니다. 투영 뒤에 평가되므로 이 절에서 정의한 별칭을 가리킬 수 있습니다. {#with-examples} ## 예제 모든 예제는 [예제 데이터셋](../../get_started/example-dataset.md)에서 실행됩니다. {#with-filter-on-a-count} ### 개수로 걸러 내기 ```cypher MATCH (p:person)-[:acted_in]->(m:movie) WITH p.name AS actor, count(m) AS films WHERE films > 1 RETURN actor, films ORDER BY films DESC, actor; ``` ``` actor | films -------------------------+------- "Keanu Reeves" | 4 "Arnold Schwarzenegger" | 3 "Carrie-Anne Moss" | 2 "Harrison Ford" | 2 "Laurence Fishburne" | 2 "Linda Hamilton" | 2 (6 rows) ``` `count(m)`이 `p.name`으로 그룹화하고, `WHERE`가 그 결과인 `films`를 검사합니다. 같은 조건을 `MATCH ... WHERE`에 쓰면 `aggregate functions are not allowed in WHERE`로 거부됩니다. {#with-add-a-column-without-losing-the-others} ### 다른 컬럼을 잃지 않고 컬럼 더하기 ```cypher MATCH (p:person)-[:directed]->(m:movie) WITH *, m.year - p.born AS age_at_release RETURN p.name AS director, m.title AS film, age_at_release ORDER BY age_at_release LIMIT 3; ``` ``` director | film | age_at_release -------------------+------------------+---------------- "James Cameron" | "The Terminator" | 30 "Lilly Wachowski" | "The Matrix" | 32 "Andrew Niccol" | "Gattaca" | 33 (3 rows) ``` `WITH *`가 `p`와 `m`을 유효 범위에 남기므로 `RETURN`이 그 속성을 계속 읽을 수 있습니다. [`LET`](let.md)은 `*` 없이 같은 일을 합니다. {#with-watch-what-a-with-drops} ### WITH가 무엇을 버리는지 보기 투영이 빼놓은 것은 그 뒤로 유효 범위 밖입니다: ```cypher MATCH (p:person)-[:acted_in]->(m:movie) WITH m RETURN p.name; ``` ``` ERROR: variable does not exist LINE 1: ...ATCH (p:person)-[:acted_in]->(m:movie) WITH m RETURN p.name; ^ ``` {#with-deduplicate-mid-pipeline} ### 파이프라인 도중에 중복 없애기 ```cypher MATCH (p:person)-[:acted_in]->(m:movie) WITH DISTINCT m.genre AS genre RETURN genre ORDER BY genre; ``` ``` genre ------------- "Action" "Adventure" "Sci-Fi" (3 rows) ``` {#with-cut-the-pipeline-down-before-matching-further} ### 더 일치시키기 전에 파이프라인 줄이기 `WITH` 뒤의 `ORDER BY`와 `LIMIT`은 다음 절이 다뤄야 하는 행 수를 줄입니다: ```cypher MATCH (m:movie) WITH m ORDER BY m.year DESC LIMIT 2 MATCH (p:person)-[:directed]->(m) RETURN m.title AS film, p.name AS director ORDER BY film; ``` ``` film | director ----------------------------+-------------------- "Blade Runner 2049" | "Denis Villeneuve" "The Matrix Resurrections" | "Lana Wachowski" (2 rows) ``` 가장 최근 영화 두 편만 둘째 `MATCH`에 도달합니다. {#with-see-that-paging-follows-the-filter} ### 페이지 나누기가 필터 뒤에 오는 것 확인하기 `WHERE`는 `WITH`에 속하고, `ORDER BY`와 `LIMIT`은 그 뒤의 절입니다. 그래서 `LIMIT`은 필터를 통과한 행을 셉니다: ```cypher MATCH (m:movie) WITH m.title AS film, m.genre AS genre WHERE genre = 'Action' ORDER BY film LIMIT 3 RETURN film, genre; ``` ``` film | genre ------------------------------+---------- "Terminator 2: Judgment Day" | "Action" "The Avengers" | "Action" "The Matrix" | "Action" (3 rows) ``` 필터를 빼면 같은 페이지 나누기가 완전히 다른 행을 고릅니다. 이제 제목순으로 앞의 세 행이 남기 때문입니다: ```cypher MATCH (m:movie) WITH m.title AS film, m.genre AS genre ORDER BY film LIMIT 3 RETURN film, genre; ``` ``` film | genre ---------------------+---------- "Avatar" | "Sci-Fi" "Blade Runner" | "Sci-Fi" "Blade Runner 2049" | "Sci-Fi" (3 rows) ``` {#with-reject-a-repeated-output-name} ### 같은 출력 이름은 거부된다 ```cypher MATCH (m:movie) WITH m.title AS film, m.genre AS film RETURN film; ``` ``` ERROR: WITH passes on "film" more than once LINE 1: MATCH (m:movie) WITH m.title AS film, m.genre AS film RETURN... ^ ``` 변수를 그대로 넘기면서 다른 것에 그 이름을 별칭으로 붙이는 것도 같은 식으로 충돌합니다. `WITH m, m.title AS m`은 `WITH passes on "m" more than once`를 냅니다. {#with-notes} ## 참고 `WHERE`는 투영 목록 바로 뒤, `ORDER BY`·`SKIP`·`LIMIT` 앞에 써야 합니다. 그보다 뒤에 두면 구문 오류입니다. `WITH ... ORDER BY film WHERE genre = 'Action'`은 파싱되지 않습니다. {#with-see-also} ## 관련 항목 - [`RETURN`](return.md) — 쿼리를 끝내는, 같은 투영 - [`LET`](let.md) {bdg-primary-line}`GQL` — 어떤 바인딩도 버리지 않고 더하기 - [`WHERE`](where.md) — `WITH`가 지닐 수 있는 조건 - [`ORDER BY`](order-by.md), [`SKIP`·`LIMIT`](skip-and-limit.md) — `WITH` 뒤에 오는 절들 - [`UNWIND`](unwind.md) — `collect()`를 되돌릴 때의 흔한 짝