WITH#

작업 행을 새 컬럼 집합으로 투영해 다음 절에 넘깁니다. 파이프라인 가운데에 있는 RETURN입니다.

개요#

WITH [ DISTINCT | ALL ] { * | expression [ AS alias ] } [, ...] [ WHERE condition ]

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

설명#

WITH는 파이프라인의 한 구역을 닫고 다음 구역을 엽니다. RETURN과 정확히 같은 방식으로 행마다 표현식을 평가하고, 그 결과 컬럼을 뒤따르는 절에 넘깁니다. 세 가지 일에 이것이 필요합니다:

  • 집계한 다음 걸러 내거나 더 일치시키기. 집계 함수는 WHERE에 올 수 없으므로, WITH에서 집계하고 그 출력을 걸러 내십시오.

  • 값을 한 번만 계산해 뒤따르는 여러 절에서 쓰기.

  • 쿼리의 비싼 부분이 실행되기 전에 DISTINCT·ORDER BY·LIMIT으로 파이프라인을 줄이기.

이것이 투영이라는 점에서 따라오는 규칙들입니다:

  • WITH는 유효 범위를 교체합니다. 투영한 것만 살아남습니다. 빼놓은 변수는 사라지고, 그것을 뒤에서 언급하면 variable does not exist가 나옵니다. 버리지 않고 더하려면 WITH *, expr AS v로 쓰거나 LET을 쓰십시오.

  • 각 출력 이름은 그 절 안에서 고유해야 합니다. 같은 이름을 두 번 투영하면 WITH passes on "..." more than once가 나옵니다. RETURN에는 그런 규칙이 없습니다.

  • 이 절의 WHERE는 투영과 집계가 끝난 뒤에 실행되므로, 집계의 별칭을 검사할 수 있습니다.

  • ORDER BY, SKIP/OFFSET, LIMIT은 WITH 뒤에 오는 별개의 절이고, 따라서 그 WHERE 뒤에도 옵니다. 필터가 먼저 실행되고, 페이지 나누기는 살아남은 것에 적용됩니다.

  • WITH는 쿼리를 시작할 수도, 끝낼 수도 없습니다. 문장 맨 앞의 WITH는 SQL의 공통 테이블 표현식이고, 그것은 이름과 괄호로 감싼 쿼리를 받는 다른 절입니다. LET에는 그런 충돌이 없어서 쿼리를 시작할 수 있습니다.

매개변수#

DISTINCT

투영한 행을 넘기기 전에 중복 행을 없앱니다.

ALL

중복 행을 그대로 둡니다. 기본값입니다.

*

유효 범위의 이름 있는 모든 바인딩을 그대로 통과시킵니다. WITH *, expr AS v처럼 다른 항목과 함께 쓰면 어떤 컬럼도 버리지 않고 컬럼을 더할 수 있습니다.

expression

유효 범위의 바인딩에 대한 Cypher 표현식이면 무엇이든 되고, 집계 함수도 됩니다.

alias

다음 절이 쓰는 이름입니다. 변수 참조만 있는 것이 아니라면 필수입니다. 뒤따르는 절이 그것을 이름으로 부를 수 있어야 하기 때문입니다.

condition

투영된 행을 걸러 내는 불리언 표현식입니다. 투영 뒤에 평가되므로 이 절에서 정의한 별칭을 가리킬 수 있습니다.

예제#

모든 예제는 예제 데이터셋에서 실행됩니다.

개수로 걸러 내기#

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로 거부됩니다.

다른 컬럼을 잃지 않고 컬럼 더하기#

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은 * 없이 같은 일을 합니다.

WITH가 무엇을 버리는지 보기#

투영이 빼놓은 것은 그 뒤로 유효 범위 밖입니다:

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;
                                                                ^

파이프라인 도중에 중복 없애기#

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 뒤의 ORDER BY와 LIMIT은 다음 절이 다뤄야 하는 행 수를 줄입니다:

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에 도달합니다.

페이지 나누기가 필터 뒤에 오는 것 확인하기#

WHERE는 WITH에 속하고, ORDER BY와 LIMIT은 그 뒤의 절입니다. 그래서 LIMIT은 필터를 통과한 행을 셉니다:

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)

필터를 빼면 같은 페이지 나누기가 완전히 다른 행을 고릅니다. 이제 제목순으로 앞의 세 행이 남기 때문입니다:

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)

같은 출력 이름은 거부된다#

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를 냅니다.

참고#

WHERE는 투영 목록 바로 뒤, ORDER BY·SKIP·LIMIT 앞에 써야 합니다. 그보다 뒤에 두면 구문 오류입니다. WITH ... ORDER BY film WHERE genre = 'Action'은 파싱되지 않습니다.

관련 항목#

  • RETURN — 쿼리를 끝내는, 같은 투영

  • LET GQL — 어떤 바인딩도 버리지 않고 더하기

  • WHERE — WITH가 지닐 수 있는 조건

  • ORDER BY, SKIP·LIMIT — WITH 뒤에 오는 절들

  • UNWIND — collect()를 되돌릴 때의 흔한 짝