# OPTIONAL MATCH
{bdg-primary-line}`GQL clause`
Matches a pattern the way `MATCH` does, but keeps an input row whose pattern
finds nothing, binding the pattern's variables to null for it.
## Synopsis
OPTIONAL MATCH pattern [, pattern ] ... [ WHERE condition ]
bold keywords · italic placeholders you supply · [ ] optional · ... repeatable. See Syntax conventions.
## Description
`OPTIONAL MATCH` takes the same patterns as [`MATCH`](match.md) and matches them
the same way. The difference is what happens when a pattern finds no match. A
plain `MATCH` drops the row. `OPTIONAL MATCH` keeps it and binds every variable
the pattern introduces to null. It is the graph counterpart of a `LEFT JOIN`.
- Variables already in scope keep their values. Only the variables the optional
pattern introduces can become null.
- A `WHERE` attached to an `OPTIONAL MATCH` is **part of the optional match**. A
row whose pattern matched but whose condition failed is kept with nulls, not
dropped. To drop it, filter after the clause with [`WITH`](with.md) or
[`FILTER`](filter.md).
- Leading a query with `OPTIONAL MATCH` yields one all-null row when the pattern
matches nothing, rather than no rows.
- Several comma-separated patterns in one clause are optional together: they
either all match or the whole clause contributes nulls.
## Parameters
pattern
: A path pattern, in the same syntax `MATCH` uses. See
[`MATCH`](match.md) for the node, edge, path and `ONLY` forms.
condition
: A boolean expression evaluated as part of the match. A row that fails it is
kept, with the pattern's variables null.
## Examples
Every example runs against [the example dataset](../../get_started/example-dataset.md).
### List people whether or not they directed anything
```cypher
MATCH (p:person) WHERE p.born > 1974
OPTIONAL MATCH (p)-[:directed]->(m:movie)
RETURN p.name AS person, m.title AS directed
ORDER BY person;
```
```
person | directed
-------------------+-----------
"Neill Blomkamp" | "Elysium"
"Ryan Gosling" |
"Sam Worthington" |
(3 rows)
```
Two of the three directed nothing, so `m` is null for them, and therefore
`m.title` is null too. The same query with a plain `MATCH` on the second line
returns one row:
```cypher
MATCH (p:person) WHERE p.born > 1974
MATCH (p)-[:directed]->(m:movie)
RETURN p.name AS person, m.title AS directed
ORDER BY person;
```
```
person | directed
------------------+-----------
"Neill Blomkamp" | "Elysium"
(1 row)
```
### Keep only the rows that failed to match
Test the optional variable for null after the clause. This finds the science
fiction films with no outgoing `related_to` edge:
```cypher
MATCH (m:movie) WHERE m.genre = 'Sci-Fi'
OPTIONAL MATCH (m)-[:related_to]->(n:movie)
WITH m, n WHERE n IS NULL
RETURN m.title AS film
ORDER BY film;
```
```
film
---------------------
"Avatar"
"Blade Runner 2049"
"Elysium"
"Gattaca"
"Inception"
"The Fifth Element"
(6 rows)
```
### See where the WHERE goes
`Jurassic Park` has one actor, Sam Neill, born 1947. With the condition inside the
optional match, the film survives with a null actor:
```cypher
MATCH (m:movie) WHERE m.genre = 'Adventure'
OPTIONAL MATCH (p:person)-[:acted_in]->(m) WHERE p.born > 1950
RETURN m.title AS film, p.name AS actor
ORDER BY film, actor;
```
```
film | actor
-----------------+-------
"Jurassic Park" |
(1 row)
```
With the same condition applied after the clause, the film is dropped:
```cypher
MATCH (m:movie) WHERE m.genre = 'Adventure'
OPTIONAL MATCH (p:person)-[:acted_in]->(m)
WITH m, p WHERE p.born > 1950
RETURN m.title AS film, p.name AS actor
ORDER BY film, actor;
```
```
film | actor
------+-------
(0 rows)
```
### Lead a query with an optional match
```cypher
OPTIONAL MATCH (m:movie {title: 'Nope'})
RETURN m;
```
```
m
---
(1 row)
```
One row, with `m` null. A plain `MATCH` here returns no rows at all.
## Notes
Reading a property of a null vertex gives null rather than an error, so
`m.title` is safe on a row the pattern did not match. Testing the variable
itself, `WHERE n IS NULL`, is the reliable way to detect that row. A matched
vertex may legitimately be missing the property you would otherwise test.
## Compatibility
### Optional blocks (ISO/IEC 39075 §14.4)
The standard's `` also allows a braced or parenthesized
block of match statements, `OPTIONAL { MATCH ... MATCH ... }`. AgensGraph accepts
`OPTIONAL` only directly in front of `MATCH`; the block form is a syntax error.
`OPTIONAL` also prefixes [`CALL`](call-subquery.md).
## See also
- [`MATCH`](match.md) — the pattern syntax, and the non-optional form
- [`WHERE`](where.md) — conditions, and where they take effect
- [`WITH`](with.md) — the clause that filters after an optional match
- [`CALL { subquery }`](call-subquery.md) — `OPTIONAL` prefixes this clause too