OPTIONAL CALL#
GQL 절 2.18에 추가
호출이 행을 내놓지 못한 입력 행을 남겨 두고, 그 호출이 반환했을 모든 것을 null로 바인딩합니다.
OPTIONAL MATCH에 대응하는 CALL 쪽 절입니다.
개요#
굵게 키워드 · 기울임 직접 채우는 자리 · [ ] 생략 가능 · ... 반복 가능. 구문 표기 규약을 참고하십시오.
설명#
OPTIONAL은 CALL의 두 형태 모두에 적용됩니다. 인라인 서브쿼리와 이름 있는
함수입니다. 그냥 쓴 CALL은 호출의 행을 파이프라인에 조인하므로, 행을 내놓지 못한 입력 행은
떨어져 나갑니다. OPTIONAL CALL은 대신 왼쪽 외부 조인으로 컴파일되고, 그것이 그 행을
보존합니다.
보존은 입력 행마다 결정됩니다. 어떤 행에 대해 아무것도 찾지 못한 상관 호출은 그 행만 null로 만들고 나머지는 그대로 둡니다.
그 호출이 바인딩했을 모든 변수가 함께 null이 되며, 타입이 무엇이든 그렇습니다. 정점, 간선, 경로, 리스트, 맵, 스칼라 모두입니다.
그 바인딩은 jsonb의
null이 아니라 실제 SQL null이므로, 검사하는 방법은IS NULL입니다.OPTIONAL은 행을 보존할 뿐 만들어 내지는 않습니다. 입력이 비어 있으면 출력도 없습니다.보존된 행은 그 뒤로 평범한 행이므로, 뒤따르는 절이 다른 행과 똑같이 그것을 곱합니다.
매개변수#
- variable_scope
서브쿼리가 볼 수 있는 바깥 변수이며,
CALL { subquery }와 정확히 같습니다.(v, w),(*),(), 또는 중괄호 안에서 가져오는WITH입니다. 가져오기 규칙은 그대로 적용됩니다.OPTIONAL CALL { … }만 쓰면 아무것도 가져오지 않습니다.- subquery
RETURN으로 끝나는 읽기 전용 쿼리입니다.- function, argument, yield_list
CALL … YIELD와 같습니다.YIELD는 여전히 필수입니다.
예제#
모든 예제는 예제 데이터셋에서 실행됩니다.
사람 셋입니다. Keanu Reeves는 연기 이력이 넷, Ryan Gosling은 하나, Christopher Nolan은 없습니다.
OPTIONAL CALL은 그 감독을 남깁니다:
MATCH (p:person) WHERE p.name IN ['Keanu Reeves', 'Ryan Gosling', 'Christopher Nolan']
OPTIONAL CALL (p) { MATCH (p)-[:acted_in]->(m:movie) RETURN m.title AS film }
RETURN p.name AS person, film ORDER BY person, film;
person | film
---------------------+----------------------------
"Christopher Nolan" |
"Keanu Reeves" | "The Matrix"
"Keanu Reeves" | "The Matrix Reloaded"
"Keanu Reeves" | "The Matrix Resurrections"
"Keanu Reeves" | "The Matrix Revolutions"
"Ryan Gosling" | "Blade Runner 2049"
(6 rows)
OPTIONAL을 빼면 같은 본문이 그 행을 완전히 잃고, 다른 두 사람은 영향을 받지 않습니다:
MATCH (p:person) WHERE p.name IN ['Keanu Reeves', 'Ryan Gosling', 'Christopher Nolan']
CALL (p) { MATCH (p)-[:acted_in]->(m:movie) RETURN m.title AS film }
RETURN p.name AS person, film ORDER BY person, film;
person | film
----------------+----------------------------
"Keanu Reeves" | "The Matrix"
"Keanu Reeves" | "The Matrix Reloaded"
"Keanu Reeves" | "The Matrix Resurrections"
"Keanu Reeves" | "The Matrix Revolutions"
"Ryan Gosling" | "Blade Runner 2049"
(5 rows)
네 행, 한 행, 그리고 보존된 한 행입니다. 이 배수는 쿼리의 성질이 아니라 입력 행마다 정해지는 것입니다.
함수가 아무것도 내놓지 않은 행 보존하기#
OPTIONAL은 이름 있는 형태에서도 같은 자리에 놓이며, 어떤 행에 대해 빈 집합을 반환하는 함수를
감당합니다:
MATCH (m:movie) WHERE m.title IN ['The Matrix', 'Avatar']
OPTIONAL CALL generate_series(1, CASE WHEN m.title = 'Avatar' THEN 0 ELSE 2 END)
YIELD generate_series AS n
RETURN m.title AS film, n ORDER BY film, n;
film | n
--------------+---
"Avatar" |
"The Matrix" | 1
"The Matrix" | 2
(3 rows)
generate_series(1, 0)은 비어 있으므로 Avatar의 행이 n이 null인 채로 살아남습니다. OPTIONAL이
없으면 그 행은 사라지고 The Matrix의 두 행만 남습니다.
보존된 바인딩 검사하기#
보존된 행에서는 본문이 반환했을 모든 변수가 null이며, 그것은 SQL null입니다:
MATCH (p:person {name: 'Christopher Nolan'})
OPTIONAL CALL (p) { MATCH (p)-[:acted_in]->(m:movie) RETURN m.title AS film, m.year AS year }
RETURN film IS NULL AS film_is_null, year IS NULL AS year_is_null;
film_is_null | year_is_null
--------------+--------------
t | t
(1 row)
행이 만들어지지 않음을 확인하기#
OPTIONAL은 입력 행을 보존합니다. 입력 행이 없으면 보존할 것이 없습니다:
MATCH (p:person {name: 'Nobody'})
OPTIONAL CALL (p) { MATCH (p)-[:acted_in]->(m:movie) RETURN m.title AS film }
RETURN p.name AS person, film;
person | film
--------+------
(0 rows)
참고#
실행 계획이 그 방식을 그대로 말해 줍니다. generate_series 스캔이
Nested Loop Left Join의 null이 될 수 있는 쪽입니다. 그 조인이 Avatar의 행을 보존합니다:
EXPLAIN (COSTS OFF)
MATCH (m:movie) WHERE m.title IN ['The Matrix', 'Avatar']
OPTIONAL CALL generate_series(1, CASE WHEN m.title = 'Avatar' THEN 0 ELSE 2 END)
YIELD generate_series AS n
RETURN m.title AS film, n;
QUERY PLAN
-----------------------------------------------------------------------------------------
Nested Loop Left Join
-> Seq Scan on movie m
Filter: (properties.'title' = ANY ('{"\"The Matrix\"","\"Avatar\""}'::jsonb[]))
-> Function Scan on generate_series
(4 rows)
어떤 본문은 항상 행을 적어도 하나 내놓고, 그런 경우 OPTIONAL은 아무것도 바꾸지 않습니다.
그룹화하지 않은 집계가 흔한 경우입니다. 그것은 항상 한 행을 내놓으므로, 이력이 없는 사람은 null이
아니라 0을 받습니다.
CALL { subquery }의 films
컬럼과 비교해 보십시오.
OPTIONAL이 완화하는 것은 그 밖에 없습니다. 본문의 쓰기 절은 여전히 구문 오류이고, 바깥 이름을
반환하는 본문은 여전히 거부되며, OPTIONAL CALL { … }만 쓰면 여전히 아무것도 가져오지 않습니다.
호환성#
GQL 적합성
GQL call procedure statement(ISO/IEC 39075:2024 §15.1)의 OPTIONAL 접두를 구현하며, 그것은
§15.2의 inline procedure call과 §15.3의 named procedure call을 모두 포함합니다.
지원 — 두 호출 형태 모두에 붙는
OPTIONAL. 입력 행마다 행을 보존하고 반환되는 모든 변수를 null로 바인딩합니다.미지원 — 데이터를 바꾸는 호출에 붙는
OPTIONAL(§13.6). 애초에 호출이 그래프에 쓸 수 없기 때문입니다.
진행 상황은 GQL 적합성 표에서 확인하십시오.
openCypher#
OPTIONAL CALL은 GQL의 구문이고, openCypher에는 OPTIONAL MATCH만 있습니다. 둘이 같은 것을
표현할 수 있는 자리에서는 결과가 일치합니다. 표준이 OPTIONAL MATCH p를
OPTIONAL CALL (imports) { MATCH p RETURN vars }로 정의하기 때문입니다. 그러므로 OPTIONAL CALL은
두 번째 장치가 아니라 더 일반적인 기본 요소입니다.
관련 항목#
OPTIONAL MATCH— 패턴에 대한, 같은 보존CALLGQL — 두 호출 형태CALL { subquery }GQL — 인라인 형태와 그 가져오기 목록CALL … YIELDGQL — 이름 있는 함수 형태