# CALL { subquery }
{bdg-primary-line}`GQL clause` {bdg-secondary-line}`Added in 2.18`
Runs a read-only subquery as a clause in the pipeline, once per input row when the
subquery imports a variable from the enclosing query.
```{important}
**A bare `CALL { … }` imports nothing.** A pattern inside the braces *declares* its
variable names, so an outer variable's name written in the body binds a fresh,
unconstrained variable of the same name rather than referring to the outer one.
Name the variables you need: `CALL (v) { … }`, `CALL (*) { … }` or
`CALL { WITH v … }`.
```
## Synopsis
[ OPTIONAL ] CALL { subquery }
[ OPTIONAL ] CALL ( [ variable [, variable ] ... ] ) { subquery }
[ OPTIONAL ] CALL ( * ) { subquery }
[ OPTIONAL ] CALL { WITH variable [, variable ] ... subquery }
bold keywords · italic placeholders you supply · [ ] optional · ... repeatable. See Syntax conventions.
## Description
`CALL { … }` evaluates the subquery and joins its result onto the working table.
The import list decides entirely what the body can see.
- With an import list, the body runs **per input row** with those variables bound,
and the rows it returns are joined to that row.
- With no imports the body is **uncorrelated**: it runs once and its result
cross-joins onto every input row.
- The body is read-only and must end with `RETURN`. Write clauses are rejected at
parse time, and a body ending in `FINISH` raises `CALL subquery must RETURN at
least one variable`.
- The names the body returns become bindings in the enclosing query. A name already
bound outside is rejected rather than shadowed. Inside the body the imported
variables keep their names as well: a `LET`, `UNWIND`, `FOR` or renaming `WITH`
that would bind one of them again is refused.
- An input row for which the body returns nothing is dropped. Use
[`OPTIONAL CALL`](optional-call.md) to keep it.
### The forms that import
Five spellings are accepted. The first two import nothing. The difference
between them and the last three is the whole point of the warning above:
| Form | Body sees |
| --- | --- |
| `CALL { … }` | Nothing |
| `CALL () { … }` | Nothing |
| `CALL (v, w) { … }` | `v` and `w` |
| `CALL (*) { … }` | Every variable in scope |
| `CALL { WITH v, w … }` | `v` and `w` |
A scope clause and an importing `WITH` may be combined. `CALL (v) { WITH w … }`
imports both. Three near-misses are syntax errors rather than alternatives:
`CALL (*) { WITH v … }`, `CALL (*, v) { … }`, and any importing `WITH` that is not
a plain list of names (`WITH *` and `WITH v AS x` are both refused).
## Parameters
variable
: A variable bound in the enclosing query, to be made visible inside the braces.
One that does not exist raises `variable "" to import into CALL does not
exist`. A scope clause with no preceding clause raises `CALL has no preceding
clause to import variables from`.
subquery
: A read-only query ending in `RETURN`. `MATCH`, `OPTIONAL MATCH`, `WITH`, `LET`,
`UNWIND`, `FOR`, `LOAD FROM`, a nested `CALL`, `DISTINCT`, `ORDER BY`,
`SKIP`/`LIMIT` and the set operators are all allowed. [`NEXT`](next.md) is not.
## Examples
Every example runs against [the example dataset](../../get_started/example-dataset.md).
### Why the import list matters
The subquery form is made for a question like this one: for each film that
somebody directed, how large was the cast? Written without an import list, it
answers a different question:
```cypher
MATCH (d:person)-[:directed]->(m:movie)
CALL { MATCH (a:person)-[:acted_in]->(m) RETURN count(a) AS cast_size }
RETURN m.title AS film, cast_size ORDER BY film LIMIT 4;
```
```
film | cast_size
---------------------+-----------
"Avatar" | 25
"Blade Runner" | 25
"Blade Runner 2049" | 25
"Elysium" | 25
(4 rows)
```
Every film has the same cast size, and 25 is the number of `acted_in` edges in the
whole graph:
```cypher
MATCH ()-[r:acted_in]->() RETURN count(r) AS acted_in_edges;
```
```
acted_in_edges
----------------
25
(1 row)
```
The `m` inside the braces is not the `m` matched outside. It is a brand-new
variable that the body's own pattern declares, constrained only by the `acted_in`
edge. So the body counts every `acted_in` edge in the graph, once and
uncorrelated, and then cross-joins that one number onto every row.
Naming the import asks the question that was intended:
```cypher
MATCH (d:person)-[:directed]->(m:movie)
CALL (m) { MATCH (a:person)-[:acted_in]->(m) RETURN count(a) AS cast_size }
RETURN m.title AS film, cast_size ORDER BY film LIMIT 4;
```
```
film | cast_size
---------------------+-----------
"Avatar" | 1
"Blade Runner" | 1
"Blade Runner 2049" | 2
"Elysium" | 1
(4 rows)
```
`CALL (*) { … }` and `CALL { WITH m … }` give the same numbers.
Nothing is reported because only *expressions* reference a variable, while
*patterns* declare one. Move the same mistake into a `WHERE` and it is caught:
```cypher
MATCH (d:person)-[:directed]->(m:movie)
CALL { MATCH (a:person) WHERE a.name = m.title RETURN count(a) AS n }
RETURN n;
```
```
ERROR: variable does not exist
LINE 2: CALL { MATCH (a:person) WHERE a.name = m.title RETURN count(...
^
```
So the silence is specific to a name reused in a pattern. That is the common
case, and the reason to write the import list every time.
### Aggregate per row without collapsing the pipeline
An aggregating body returns exactly one row for every input row, even when the
value it computes is zero, so the outer row count is unchanged:
```cypher
MATCH (p:person) WHERE p.name IN ['Keanu Reeves', 'Christopher Nolan']
CALL (p) { MATCH (p)-[:acted_in]->(m:movie) RETURN count(m) AS films }
RETURN p.name AS person, films ORDER BY person;
```
```
person | films
---------------------+-------
"Christopher Nolan" | 0
"Keanu Reeves" | 4
(2 rows)
```
### Compute one number once
An empty scope clause states plainly that the body is uncorrelated. Write it
when the body is a constant of the query:
```cypher
MATCH (p:person {name: 'Keanu Reeves'})
CALL () { MATCH (m:movie) RETURN count(m) AS movies }
RETURN p.name AS person, movies;
```
```
person | movies
----------------+--------
"Keanu Reeves" | 18
(1 row)
```
### Import several variables
Every named variable is visible, and the body may use only some of them:
```cypher
MATCH (p:person {name: 'Keanu Reeves'}), (q:person {name: 'Carrie-Anne Moss'})
CALL (p, q) { MATCH (p)-[:acted_in]->(m:movie)<-[:acted_in]-(q) RETURN count(m) AS shared }
RETURN shared;
```
```
shared
--------
2
(1 row)
```
## Notes
A correlated body is not a per-row subquery in the plan. The planner pulls it up,
so the query above plans as the same join an inline pattern would produce. That
is a `Hash Join` over `person`, `acted_in` and `movie`, identical to
`MATCH (p:person)-[:acted_in]->(m:movie)`. Only a body the planner cannot flatten,
such as an aggregating one, stays a per-row lateral join with an `Aggregate` under
a `Nested Loop`.
Write clauses are refused as a syntax error at the write keyword, one for each
kind: `CREATE`, `INSERT`, `MERGE`, `SET`, `REMOVE`, `DELETE` and `DETACH DELETE`.
A body that returns a name the outer query already binds raises `variable ""
returned by the CALL subquery is already bound in the outer query`. It would
shadow the outer binding for everything that follows. Alias it in the body's
`RETURN`.
## Compatibility
```{admonition} GQL conformance
:class: gql-conformance
Implements the GQL *inline procedure call* (ISO/IEC 39075:2024 §15.2) under the
*call procedure statement* of §15.1, in the query position of §14.5.
- **Supported** — the *variable scope clause* with a binding-variable list and in
its empty `()` form, nesting, and the `OPTIONAL` prefix.
- **Not supported** — a data-modifying body (§13.6, *call data-modifying procedure
statement*).
- **Deviation, and the one to know** — §15.2 Syntax Rule 3 says that when the
variable scope clause is *absent*, the call is rewritten with a scope clause
listing **every** field of the incoming working record. Under the standard a bare
`CALL { … }` therefore imports everything, exactly like `CALL (*) { … }`.
AgensGraph treats an absent scope clause as importing nothing, like `CALL () { … }`.
- **Extension** — `(*)` is not in the standard's *binding variable reference list*,
and neither is the importing `WITH`. Both come from openCypher.
Track status in the [GQL conformance matrix](../../appendix/gql-conformance.md).
```
### openCypher
openCypher requires the same import list, but reports its absence: referring to an
undeclared outer variable inside `CALL { }` is an error there, not a silent
rebinding. Code moved from openCypher keeps working, since `CALL (v) { }`,
`CALL (*) { }` and `CALL { WITH v … }` all mean what they do there. A bare
`CALL { }` that openCypher rejected will run here and answer differently.
## See also
- [`CALL`](call.md) {bdg-secondary-line}`GQL` — both call forms
- [`OPTIONAL CALL`](optional-call.md) {bdg-secondary-line}`GQL` — keep a row the body returned nothing for
- [`CALL … YIELD`](call-yield.md) {bdg-secondary-line}`GQL` — call a named function instead
- [Subquery value expressions](subquery-expressions.md) {bdg-secondary-line}`GQL` — a subquery in an expression
- [GQL conformance matrix](../../appendix/gql-conformance.md)