diff --git a/pages/querying/clauses/create.mdx b/pages/querying/clauses/create.mdx
index 0dd62b22a..70be640dc 100644
--- a/pages/querying/clauses/create.mdx
+++ b/pages/querying/clauses/create.mdx
@@ -22,6 +22,7 @@ more details.
1.2. [Creating a node with properties](#12-creating-a-node-with-properties)
1.3. [Creating multiple nodes](#13-creating-multiple-nodes)
1.4. [Creating node labels dynamically](#14-creating-node-labels-dynamically)
+ 1.5. [Creating a node from an already-declared variable](#15-creating-a-node-from-an-already-declared-variable)
2. [Creating relationships](#2-creating-relationships)
2.1. [Creating a relationship between two nodes](#21-creating-a-relationship-between-two-nodes)
2.2. [Creating a relationship with properties](#22-creating-a-relationship-with-properties)
@@ -140,6 +141,44 @@ Output:
This functionality can especially be useful when importing data from CSV or other sources, since at that point you can inject the arbitrary labels
into the graph.
+### 1.5. Creating a node from an already-declared variable
+
+A node in a `CREATE` pattern may reuse a variable the query has already bound, so
+that a relationship can be attached to it. The queries below use the node created
+in [1.2](#12-creating-a-node-with-properties):
+
+```cypher
+MATCH (c:Country {name: 'San Marino'})
+CREATE (c)<-[:LIVING_IN]-(p:Person {name: 'Petra'})
+RETURN p.name AS name;
+```
+
+Output:
+```nocopy
++---------+
+| name |
++---------+
+| "Petra" |
++---------+
+```
+
+Such a node may not give the variable labels or properties, because the node it
+names already exists:
+
+```cypher
+MATCH (c:Country {name: 'San Marino'})
+CREATE (c {population: 34000});
+```
+
+Output:
+```nocopy
+Cannot create node 'c' with labels or properties, because it is already declared.
+```
+
+The rule holds whether the properties are written as a literal map or supplied as
+a parameter, and it applies to [`MERGE`](/querying/clauses/merge) as well. Use
+[`SET`](/querying/clauses/set) to change a node that already exists.
+
## 2. Creating relationships
### 2.1. Creating a relationship between two nodes
diff --git a/pages/querying/clauses/match.mdx b/pages/querying/clauses/match.mdx
index eeeb97b1f..2cf2f58f5 100644
--- a/pages/querying/clauses/match.mdx
+++ b/pages/querying/clauses/match.mdx
@@ -30,6 +30,7 @@ The `MATCH` clause is used to obtain data from the database by matching it to a
4. [Using multiple MATCH clauses](#4-using-multiple-match-clauses)
4.1. [Cartesian product of nodes](#41-cartesian-product-of-nodes)
4.2. [Creating a list](#42-creating-a-list)
+ 4.3. [Matching a variable that is already bound](#43-matching-a-variable-that-is-already-bound)
@@ -476,6 +477,79 @@ Output:
The `OPTIONAL MATCH` clause bypasses the empty set and the query returns only non-empty sets. Therefore, the output of the query is a list containing only the results of the first `MATCH` clause.
+### 4.3. Matching a variable that is already bound
+
+A pattern may hold nothing but a variable the query has already bound. Such a
+pattern does not scan the graph — it matches on the value bound to that name:
+
+```cypher
+MATCH (p:Person)
+MATCH (p)
+RETURN p.name AS name
+ORDER BY name;
+```
+
+Output:
+
+```nocopy
++---------+
+| name |
++---------+
+| "Anna" |
+| "Harry" |
+| "John" |
++---------+
+```
+
+A node matches and the row is kept. A `null`, which an `OPTIONAL MATCH` leaves
+behind when nothing matched, matches nothing and the row is dropped:
+
+```cypher
+MATCH (p:Person)
+OPTIONAL MATCH (p)-[:LIVING_IN]->(c:Country {continent: 'Asia'})
+WITH p, c
+MATCH (c)
+RETURN p.name AS name, c.name AS country
+ORDER BY name;
+```
+
+Output:
+
+`Empty set`
+
+No person lives in an Asian country, so `c` is `null` on every row and `MATCH (c)`
+keeps none of them. Without the `MATCH (c)`, the query returns all three people
+with a `null` country.
+
+A value that is neither a node nor `null` raises an error:
+
+```cypher
+MATCH (p:Person)
+WITH p.name AS p
+MATCH (p)
+RETURN p;
+```
+
+Output:
+
+```nocopy
+Expected a node for 'p', but got string.
+```
+
+
+
+This applies wherever a pattern appears — a top-level `MATCH`, a `CALL {}`
+subquery, and the body of a [subquery
+expression](/querying/subquery-expressions). Before Memgraph 3.14 a pattern
+holding only a bound variable was ignored, so the row passed through whatever the
+variable held. Queries that carried a `null` or a non-node value through such a
+pattern now return fewer rows or raise an error.
+
+A pattern that also states a label or a property, such as `MATCH (p:Person)`, is
+unaffected — it already raised on a non-node value.
+
+
+
## Dataset queries
We encourage you to try out the examples by yourself.
diff --git a/pages/querying/clauses/merge.mdx b/pages/querying/clauses/merge.mdx
index 3b7529a00..1b4ef39af 100644
--- a/pages/querying/clauses/merge.mdx
+++ b/pages/querying/clauses/merge.mdx
@@ -34,7 +34,8 @@ more details.
3.4. [Merging with SET](#34-merging-with-set)
3.5. [Combination of clauses](#35-combination-of-clauses)
4. [Errors related to invalid MERGE usage](#4-errors-related-to-invalid-merge-usage)
- 4.1. [Merging a null property](#41-merging-a-null-property)
+ 4.1. [Merging a null property](#41-merging-a-null-property)
+ 4.2. [Merging a node from an already-declared variable](#42-merging-a-node-from-an-already-declared-variable)
## Data Set
@@ -328,3 +329,24 @@ Due to Memgraph having the same behavior for null types, which also corresponds
we do not support this behavior.
This applies to both node and edge properties. The check is evaluated at runtime.
To mitigate this issue, try modifying the query using `ON CREATE SET`, `ON MATCH SET`, or just `SET` after the `MERGE` clause.
+
+### 4.2. Merging a node from an already-declared variable
+
+A node in a `MERGE` pattern may reuse a variable the query has already bound, so
+that a relationship can be merged onto it. Such a node may not give the variable
+labels or properties, because the node it names already exists:
+
+```cypher
+MATCH (c:Country {name: 'Germany'})
+MERGE (c:Visited);
+```
+will result in the following error
+
+```
+Cannot create node 'c' with labels or properties, because it is already declared.
+```
+
+The rule holds whether the properties are written as a literal map or supplied as
+a parameter, and it applies to [`CREATE`](/querying/clauses/create) as well. Use
+`ON CREATE SET`, `ON MATCH SET` or [`SET`](/querying/clauses/set) to change a node
+that already exists.
diff --git a/pages/querying/subquery-expressions.mdx b/pages/querying/subquery-expressions.mdx
index 229b931b8..0ee56f896 100644
--- a/pages/querying/subquery-expressions.mdx
+++ b/pages/querying/subquery-expressions.mdx
@@ -402,9 +402,8 @@ Output:
### The bare pattern shorthand
`EXISTS` and `COUNT` accept a bare pattern in place of a full body, which is a
-shorter way to write a check or a count over one pattern. The pattern cannot
-introduce names of its own — a variable already bound outside may appear in it,
-and acts as a join:
+shorter way to write a check or a count over one pattern. A variable already
+bound outside may appear in it, and acts as a join:
```cypher
MATCH (p:Person)
@@ -427,10 +426,32 @@ Output:
+---------+-------+---------+
```
-The shorthand holds a pattern and nothing else, so a filter or any other clause
-needs the `MATCH` form — `COUNT { MATCH (p)-[r:KNOWS]->() WHERE r.since < 2015 }`.
-`COLLECT` has no shorthand, since a bare pattern returns no column for it to
-gather.
+The shorthand takes everything a `MATCH` pattern takes: a variable it declares
+itself, a trailing `WHERE`, several patterns separated by commas, a named path,
+and a pattern holding only a node.
+
+```cypher
+MATCH (p:Person)
+RETURN p.name AS name,
+ COUNT { (p)-[r:KNOWS]->(f:Person) WHERE r.since < 2015 } AS early
+ORDER BY name;
+```
+
+Output:
+
+```nocopy
++---------+-------+
+| name | early |
++---------+-------+
+| "Alice" | 1 |
+| "Bob" | 0 |
+| "Carol" | 0 |
+| "Dave" | 0 |
++---------+-------+
+```
+
+Any other clause still needs the `MATCH` form. `COLLECT` has no shorthand, since
+a bare pattern returns no column for it to gather.
### Correlation with the enclosing query
@@ -479,6 +500,74 @@ Output:
Variables introduced inside the body are scoped to it and are not available after
the subquery expression.
+A pattern in the body may hold nothing but a correlated variable. Such a pattern
+matches on the value bound to that name rather than scanning the graph: a node
+matches, a `null` matches nothing, and a value that is neither raises an error.
+
+```cypher
+MATCH (p:Person)
+OPTIONAL MATCH (p)-[:KNOWS]->(f:Person)
+WITH p, f
+RETURN p.name AS name, EXISTS { (f) } AS bound
+ORDER BY name, bound;
+```
+
+Output:
+
+```nocopy
++---------+-------+
+| name | bound |
++---------+-------+
+| "Alice" | true |
+| "Alice" | true |
+| "Bob" | true |
+| "Carol" | false |
+| "Dave" | false |
++---------+-------+
+```
+
+Carol and Dave know nobody, so `f` is `null` on their rows and `EXISTS { (f) }`
+is `false`. This is the same rule a top-level [`MATCH`](/querying/clauses/match)
+follows.
+
+A named path inside the body may not take its name from a variable declared
+outside the body. The body writes into the frame it shares with its caller, so
+one name cannot mean the caller's value in one place and the body's own path in
+another:
+
+```cypher
+MATCH (p:Person)
+WITH p, p.name AS path
+RETURN COUNT { MATCH path = (p)-[:KNOWS]->() } AS c;
+```
+
+Output:
+
+```nocopy
+Cannot name a pattern 'path' in COUNT, because that variable is already declared outside it.
+```
+
+Give the path a name of its own, and it works:
+
+```cypher
+MATCH (p:Person)
+RETURN COUNT { MATCH q = (p)-[:KNOWS]->() } AS c
+ORDER BY c;
+```
+
+Output:
+
+```nocopy
++---+
+| c |
++---+
+| 0 |
+| 0 |
+| 1 |
+| 2 |
++---+
+```
+
### The body's RETURN decides the result
The body is a query, and its final `RETURN` shapes the row set that the