|
1 | 1 | = Sequential queries (`NEXT`) |
2 | 2 | :description: Information about how to use `NEXT` to construct sequential queries in Cypher. |
| 3 | +:table-caption!: |
3 | 4 | :page-role: new-2025.06 |
4 | 5 |
|
5 | 6 | `NEXT` allows for linear composition of queries into a sequence of smaller, self-contained segments while making return values from one segment available in the next. |
6 | 7 |
|
7 | | -`NEXT` has a number of benefits: |
| 8 | +`NEXT` has the following benefits: |
8 | 9 |
|
9 | 10 | * `NEXT` can improve the modularity and readability of complex queries. |
10 | | -* `NEXT` reduces the need to rely on the xref:clauses/call.adoc[CALL] and xref:clauses/with.adoc[] clauses to construct complex queries. |
11 | | -* `NEXT` improves the usability of xref:queries/composed-queries/conditional-queries.adoc[conditional] and xref:queries/composed-queries/combined-queries.adoc[UNION] queries. |
| 11 | +* `NEXT` can be used instead of xref:subqueries/call-subquery.adoc[] and the xref:clauses/with.adoc[] clause to construct complex queries. |
| 12 | +* `NEXT` can improve the usability of xref:queries/composed-queries/conditional-queries.adoc[conditional] and xref:queries/composed-queries/combined-queries.adoc[UNION] queries. |
12 | 13 |
|
13 | 14 | `NEXT` was introduced as part of Cypher's xref:appendix/gql-conformance/index.adoc[]. |
14 | 15 |
|
|
19 | 20 |
|
20 | 21 | The following graph is used for the examples on this page: |
21 | 22 |
|
22 | | -image::conditional_query_graph.svg[width="700",role="middle"] |
| 23 | +image::with_clause.svg[width="600",role="middle"] |
23 | 24 |
|
24 | | -To recreate the graph, run the following query against an empty Neo4j database: |
| 25 | +To recreate the graph, run the following query against an empty Neo4j database. |
25 | 26 |
|
26 | 27 | [source, cypher, role=test-setup] |
27 | 28 | ---- |
28 | | -CREATE (alice:Person {name:'Alice', age: 65}), |
29 | | - (bob:Person {name: 'Bob', age: 25}), |
30 | | - (charlie:Person {name: 'Charlie', age: 61}), |
31 | | - (daniel:Person {name: 'Daniel', age: 39}), |
32 | | - (eskil:Person {name: 'Eskil', age: 39}), |
33 | | - (bob)-[:WORKS_FOR]->(alice), |
34 | | - (alice)-[:WORKS_FOR]->(daniel), |
35 | | - (charlie)-[:WORKS_FOR]->(daniel), |
36 | | - (bob)-[:LOVES]->(eskil), |
37 | | - (charlie)-[:LOVES]->(alice) |
| 29 | +CREATE (techCorp:Supplier {name: 'TechCorp', email: '[email protected]'}), |
| 30 | + (foodies:Supplier {name: 'Foodies Inc.', email: '[email protected]'}), |
| 31 | + |
| 32 | + (laptop:Product {name: 'Laptop', price: 1000}), |
| 33 | + (phone:Product {name: 'Phone', price: 500}), |
| 34 | + (headphones:Product {name: 'Headphones', price: 250}), |
| 35 | + (chocolate:Product {name: 'Chocolate', price: 5}), |
| 36 | + (coffee:Product {name: 'Coffee', price: 10}), |
| 37 | + |
| 38 | + (amir:Customer {firstName: 'Amir', lastName: 'Rahman', email: '[email protected]', discount: 0.1}), |
| 39 | + (keisha:Customer {firstName: 'Keisha', lastName: 'Nguyen', email: '[email protected]', discount: 0.2}), |
| 40 | + (mateo:Customer {firstName: 'Mateo', lastName: 'Ortega', email: '[email protected]', discount: 0.05}), |
| 41 | + (hannah:Customer {firstName: 'Hannah', lastName: 'Connor', email: '[email protected]', discount: 0.15}), |
| 42 | + (leila:Customer {firstName: 'Leila', lastName: 'Haddad', email: '[email protected]', discount: 0.1}), |
| 43 | + (niko:Customer {firstName: 'Niko', lastName: 'Petrov', email: '[email protected]', discount: 0.25}), |
| 44 | + (yusuf:Customer {firstName: 'Yusuf', lastName: 'Abdi', email: '[email protected]', discount: 0.1}), |
| 45 | +
|
| 46 | + (amir)-[:BUYS {date: date('2024-10-09')}]->(laptop), |
| 47 | + (amir)-[:BUYS {date: date('2025-01-10')}]->(chocolate), |
| 48 | + (keisha)-[:BUYS {date: date('2023-07-09')}]->(headphones), |
| 49 | + (mateo)-[:BUYS {date: date('2025-03-05')}]->(chocolate), |
| 50 | + (mateo)-[:BUYS {date: date('2025-03-05')}]->(coffee), |
| 51 | + (mateo)-[:BUYS {date: date('2024-04-11')}]->(laptop), |
| 52 | + (hannah)-[:BUYS {date: date('2023-12-11')}]->(coffee), |
| 53 | + (hannah)-[:BUYS {date: date('2024-06-02')}]->(headphones), |
| 54 | + (leila)-[:BUYS {date: date('2023-05-17')}]->(laptop), |
| 55 | + (niko)-[:BUYS {date: date('2025-02-27')}]->(phone), |
| 56 | + (niko)-[:BUYS {date: date('2024-08-23')}]->(headphones), |
| 57 | + (niko)-[:BUYS {date: date('2024-12-24')}]->(coffee), |
| 58 | + (yusuf)-[:BUYS {date: date('2024-12-24')}]->(chocolate), |
| 59 | + (yusuf)-[:BUYS {date: date('2025-01-02')}]->(laptop), |
| 60 | + |
| 61 | + (techCorp)-[:SUPPLIES]->(laptop), |
| 62 | + (techCorp)-[:SUPPLIES]->(phone), |
| 63 | + (techCorp)-[:SUPPLIES]->(headphones), |
| 64 | + (foodies)-[:SUPPLIES]->(chocolate), |
| 65 | + (foodies)-[:SUPPLIES]->(coffee) |
| 66 | +---- |
| 67 | + |
| 68 | + |
| 69 | +== Composing queries with `NEXT` |
| 70 | + |
| 71 | +.`NEXT` syntax |
| 72 | +[source, cypher] |
| 73 | +---- |
| 74 | +<Query1> |
| 75 | +
|
| 76 | +NEXT |
| 77 | +
|
| 78 | +<Query2> |
| 79 | +
|
| 80 | +NEXT |
| 81 | +
|
| 82 | +<Query3> |
| 83 | +---- |
| 84 | + |
| 85 | + |
| 86 | +=== Passing values to subsequent queries |
| 87 | + |
| 88 | +In the following example, `NEXT` passes the variable `customer` to the second query: |
| 89 | + |
| 90 | +.Passing a variable to another query via `NEXT` |
| 91 | +==== |
| 92 | +.Query |
| 93 | +[source, cypher] |
38 | 94 | ---- |
| 95 | +MATCH (c:Customer)-[:BUYS]->(:Product {name: 'Chocolate'}) |
| 96 | +RETURN c AS customer |
| 97 | +
|
| 98 | +NEXT |
39 | 99 |
|
| 100 | +RETURN customer.firstName AS chocolateCustomer |
| 101 | +---- |
40 | 102 |
|
41 | | -[[sequential-syntax]] |
42 | | -== Syntax |
| 103 | +.Result |
| 104 | +[role="queryresult",options="header,footer",cols="1*<m"] |
| 105 | +|=== |
| 106 | +| chocolateCustomer |
43 | 107 |
|
44 | | -Lorem ipsum. |
| 108 | +| "Amir" |
| 109 | +| "Mateo" |
| 110 | +| "Yusuf" |
45 | 111 |
|
| 112 | +1+d|Rows: 3 |
| 113 | +|=== |
| 114 | +==== |
46 | 115 |
|
47 | | -[[sequential-rules]] |
48 | | -== Rules |
49 | 116 |
|
50 | | -Lorem ipsum. |
| 117 | +.Passing multiple variables to another query via `NEXT` |
| 118 | +==== |
| 119 | +.Query |
| 120 | +[source, cypher] |
| 121 | +---- |
| 122 | +MATCH (c:Customer)-[:BUYS]->(p:Product {name: 'Chocolate'}) |
| 123 | +RETURN c AS customer, p AS product |
| 124 | + |
| 125 | +NEXT |
| 126 | + |
| 127 | +RETURN customer.firstName AS chocolateCustomer, |
| 128 | + product.price * (1 - customer.discount) AS chocolatePrice |
51 | 129 |
|
52 | | -.Not allowed: not aliasing returned expressions |
53 | | -[source, cypher, role=test-fail] |
54 | 130 | ---- |
55 | | -WHEN true THEN RETURN 2 |
56 | | -ELSE RETURN 3 |
| 131 | +
|
| 132 | +.Result |
| 133 | +[role="queryresult",options="header,footer",cols="2*<m"] |
| 134 | +|=== |
| 135 | +| chocolateCustomer | chocolatePrice |
| 136 | +
|
| 137 | +| "Amir" | 4.5 |
| 138 | +| "Mateo" | 4.75 |
| 139 | +| "Yusuf" | 4.5 |
| 140 | +
|
| 141 | +2+d|Rows: 3 |
| 142 | +|=== |
| 143 | +==== |
| 144 | + |
| 145 | + |
| 146 | + |
| 147 | +[NOTE] |
| 148 | +==== |
| 149 | +Expressions in a `RETURN` clause must be aliased with an `AS` or a `LET` when they are followed by a `NEXT` clause. |
| 150 | +==== |
| 151 | + |
| 152 | +// is an example necessary? not a fan of negative examples in general |
| 153 | + |
| 154 | + |
| 155 | +== Interactions with `CALL` subqueries and `WITH` |
| 156 | + |
| 157 | +You can use `NEXT` to rewrite queries containing `CALL` subqueries or a `WITH` clause. |
| 158 | + |
| 159 | +.Rewriting a query with a `CALL` subquery |
| 160 | +==== |
| 161 | +[cols="1,1"] |
| 162 | +|=== |
| 163 | +a| |
| 164 | +.`CALL` subquery |
| 165 | +[source, cypher] |
57 | 166 | ---- |
| 167 | +LET a = 1 |
| 168 | +WITH a |
58 | 169 |
|
| 170 | +CALL(*) { |
| 171 | + LET b = a + 1 |
| 172 | + RETURN b |
| 173 | + UNION |
| 174 | + LET b = a + 2 |
| 175 | + RETURN b |
| 176 | +} |
| 177 | +WITH a, b |
59 | 178 |
|
60 | | -== Using `NEXT` instead of `CALL` |
| 179 | +LET c = b + 1 |
| 180 | +RETURN a, b, c |
| 181 | +---- |
| 182 | +a| |
| 183 | +.`NEXT` |
| 184 | +[source, cypher] |
| 185 | +---- |
| 186 | +LET a = 1 |
| 187 | +RETURN a |
61 | 188 |
|
62 | | -Lorem ipsum. |
| 189 | +NEXT |
63 | 190 |
|
| 191 | +LET b = a + 1 |
| 192 | +RETURN a, b |
| 193 | +UNION |
| 194 | +LET b = a + 2 |
| 195 | +RETURN a, b |
64 | 196 |
|
65 | | -== Using `NEXT` instead of `WITH` |
| 197 | +NEXT |
66 | 198 |
|
67 | | -Lorem ipsum. |
| 199 | +LET c = b + 1 |
| 200 | +RETURN a, b, c |
| 201 | +---- |
| 202 | +|=== |
| 203 | +==== |
68 | 204 |
|
69 | 205 |
|
| 206 | + |
| 207 | +.Rewriting a `WITH` query |
| 208 | +==== |
| 209 | +[cols="1,1"] |
| 210 | +|=== |
| 211 | +a| |
| 212 | +.`WITH` |
| 213 | +[source, cypher] |
| 214 | +---- |
| 215 | +LET a = 1 |
| 216 | +WITH a |
| 217 | +LET b = a + 1 |
| 218 | +WITH a, b |
| 219 | +LET c = a + b + 1 |
| 220 | +WITH b, c |
| 221 | +LET d = b + c |
| 222 | +RETURN d |
| 223 | +---- |
| 224 | +a| |
| 225 | +.`NEXT` |
| 226 | +[source, cypher] |
| 227 | +---- |
| 228 | +LET a = 1 |
| 229 | +RETURN a |
| 230 | +
|
| 231 | +NEXT |
| 232 | +
|
| 233 | +LET b = a + 1 |
| 234 | +RETURN a, b |
| 235 | +
|
| 236 | +NEXT |
| 237 | +
|
| 238 | +LET c = a + b + 1 |
| 239 | +RETURN b, c |
| 240 | +
|
| 241 | +NEXT |
| 242 | +
|
| 243 | +LET d = b + c |
| 244 | +RETURN d |
| 245 | +---- |
| 246 | +|=== |
| 247 | +==== |
| 248 | + |
| 249 | +Variables which are local to a query and which are not explicitly returned are not accessible by its subsequent query in the context of `NEXT`. |
| 250 | +This allows you to control variable scope similarly to what you can do with `WITH`, see xref:clauses/with.adoc#variable-scope[Control variables in scope]. |
| 251 | + |
| 252 | +[NOTE] |
| 253 | +==== |
| 254 | +`NEXT` cannot be used inside a `CALL` subquery that uses the (deprecated) xref:subqueries/call-subquery.adoc#importing-with[importing `WITH`] syntax. |
| 255 | +==== |
| 256 | + |
70 | 257 | == Interactions with conditional queries |
71 | 258 |
|
72 | | -Lorem ipsum. |
| 259 | +// use example with the example data set instead |
| 260 | + |
| 261 | +.`NEXT` in a conditional query |
| 262 | +==== |
| 263 | +.Query |
| 264 | +[source, cypher] |
| 265 | +---- |
| 266 | +MATCH (n) |
| 267 | +RETURN n |
| 268 | +
|
| 269 | +NEXT |
| 270 | +
|
| 271 | +WHEN n.x > 2 THEN |
| 272 | + RETURN "large number" AS msg |
| 273 | +WHEN n.x > 1 THEN |
| 274 | + RETURN "small number" AS msg |
| 275 | +ELSE |
| 276 | + RETURN "tiny number" AS msg |
| 277 | +
|
| 278 | +---- |
| 279 | +
|
| 280 | +.Result |
| 281 | +[role="queryresult",options="header,footer",cols="1*<m"] |
| 282 | +|=== |
| 283 | +| chocolateCustomer |
| 284 | +
|
| 285 | +| "Amir" |
| 286 | +| "Mateo" |
| 287 | +| "Yusuf" |
| 288 | +
|
| 289 | +1+d|Rows: 3 |
| 290 | +|=== |
| 291 | +==== |
73 | 292 |
|
74 | 293 |
|
75 | 294 | == Interactions with `UNION` queries |
76 | 295 |
|
77 | | -Lorem ipsum. |
| 296 | +// use example with the example data set instead |
| 297 | + |
| 298 | +.`NEXT` in a query using `UNION` |
| 299 | +==== |
| 300 | +.Query |
| 301 | +[source, cypher] |
| 302 | +---- |
| 303 | +RETURN 1 AS a |
| 304 | +UNION |
| 305 | +RETURN 2 AS a |
| 306 | +
|
| 307 | +NEXT |
| 308 | +
|
| 309 | +RETURN a, a + 1 AS b |
| 310 | +UNION |
| 311 | +RETURN a, a + 2 AS b |
| 312 | +---- |
| 313 | +
|
| 314 | +.Result |
| 315 | +[role="queryresult",options="header,footer",cols="1*<m"] |
| 316 | +|=== |
| 317 | +| chocolateCustomer |
| 318 | +
|
| 319 | +| "Amir" |
| 320 | +| "Mateo" |
| 321 | +| "Yusuf" |
| 322 | +
|
| 323 | +1+d|Rows: 3 |
| 324 | +|=== |
| 325 | +==== |
0 commit comments