条件查询 (WHEN)仅限 Cypher 25Neo4j 2025.06 引入
WHEN 与 THEN 和 ELSE 配合使用,可以根据特定条件执行查询的不同分支。通过这种方式,它实现了类似于其他编程语言中 IF 语句的控制流机制。
有关在表达式中使用 WHEN 分支的信息,请参阅 条件表达式 (CASE) |
示例图
以下图表用于下方的示例
要重新创建该图,请在空的 Neo4j 数据库中运行以下查询
CREATE (alice:Person {name:'Alice', age: 65}),
(bob:Person {name: 'Bob', age: 25}),
(charlie:Person {name: 'Charlie', age: 61}),
(daniel:Person {name: 'Daniel', age: 39}),
(eskil:Person {name: 'Eskil', age: 39}),
(bob)-[:WORKS_FOR]->(alice),
(alice)-[:WORKS_FOR]->(daniel),
(charlie)-[:WORKS_FOR]->(daniel),
(bob)-[:LOVES]->(eskil),
(charlie)-[:LOVES]->(alice)
独立 WHEN 分支
WHEN 分支的语法WHEN predicate THEN [{]
<conditionalQuery>
[}]
[WHEN ...]*
[ELSE [{]
<conditionalQuery>
[}]]
第一个谓词计算结果为 true 的分支将被执行。如果没有任何 WHEN 分支被执行且存在 ELSE 分支,则执行 ELSE 分支。如果没有任何 WHEN 分支计算结果为 true 且不存在 ELSE 分支,则不会执行任何分支,也不会产生任何行。以下示例展示了此逻辑。
WHEN false THEN RETURN 1 AS x
WHEN true THEN RETURN 2 AS x
WHEN true THEN RETURN 3 AS x
ELSE RETURN 3 AS x
由于第二个 WHEN 分支为 true,它将执行,而前面的分支(为 false)和后续的 WHEN 分支(即使为 true)以及 ELSE 分支都将被跳过。
| x |
|---|
|
行:1 |
WHEN 分支中条件执行查询WHEN true THEN {
MATCH (n:Person) WHERE n.name STARTS WITH "A"
RETURN n.name AS name
}
ELSE {
MATCH (n:Person)
RETURN n.name AS name
}
上述示例和下述示例中包含的 {} 并非必须(除非明确说明),但它们明确了查询中不同的条件分支。 |
| 名称 (name) |
|---|
|
行:1 |
规则
与 UNION 类似,WHEN/ELSE 结构的所有部分中,列的数量和名称必须完全相同。这意味着返回的表达式必须使用 AS 进行别名命名。
WHEN true THEN RETURN 2
ELSE RETURN 3
WHEN true THEN RETURN 2 AS x
ELSE RETURN 3 AS y
WHEN true THEN RETURN 2 AS x, 3 AS y
ELSE RETURN 3 AS x
WHEN 也不能作为查询中的常规子句定位。例如,它不能紧接在 MATCH 子句之后。
WHEN 结构用作常规子句MATCH (n)-[:WORKS_FOR]->(manager:Person)
WHEN manager IS NULL THEN {
MERGE (n)-[:WORKS_FOR]->(newManager: Person {name: 'Peter', age: 36})
}
RETURN n.name AS employees,
m.name AS manager,
newManager.name AS newManagerNode
相反,如果 WHEN 结构是大型查询的一部分,则必须将其置于子查询内和/或组合 UNION 查询的不同侧。
条件子查询
WHEN 可以用在一个或多个 CALL 子查询 中,仅当指定的条件计算结果为 true 时才执行一组操作。
CALL 子查询的语法[<outerQuery>]
<callSubquery> {
WHEN predicate THEN [{]
<conditionalQuery>
[}]
[WHEN ...]*
[ELSE [{]
<conditionalQuery>
[}]]
}
[<callSubquery> ...]*
[<outerQuery>]
CALL 子查询在此示例中,WHEN 用于为条件 (manager IS NULL) 计算结果为 true 的每一行执行一个 CALL 子查询。
CALL 子查询MATCH (n:Person)
OPTIONAL MATCH (n)-[:WORKS_FOR]->(manager:Person)
CALL (*) {
WHEN manager IS NULL THEN {
MERGE (newManager: Person {name: 'Peter', age: 36})
MERGE (n)-[:WORKS_FOR]->(newManager)
RETURN newManager, n.name AS employee
}
}
RETURN newManager.name AS newManager,
collect(employee) AS employees
由于只有 Daniel 和 Eskil 没有向外的 WORKS_FOR 关系,他们现在已被连接为新的 Peter 节点的员工。
| newManager | employees |
|---|---|
|
|
行:1 |
|
CALL 子查询不相关的条件 CALL 子查询可以依次链式执行,每个子查询的执行都取决于一组定义的条件。
此示例使用条件逻辑为个人分配年龄组。第二个 CALL 随后会收集其经理(他们 WORK_FOR 的对象)的姓名和年龄组,但仅针对那些经理比自己年长的个人。
CALL 子查询MATCH (n:Person)
OPTIONAL MATCH (n)-[r:WORKS_FOR]->(m:Person)
CALL (*) {
WHEN n.age > 60 THEN {
SET n.ageGroup = 'Veteran'
RETURN n.ageGroup AS ageGroup
}
WHEN n.age >= 35 AND n.age <= 59 THEN {
SET n.ageGroup = 'Senior'
RETURN n.ageGroup AS ageGroup
}
ELSE {
SET n.ageGroup = 'Junior'
RETURN n.ageGroup AS ageGroup
}
}
CALL (*) {
WHEN m.age > n.age THEN {
RETURN collect([m.name, m.ageGroup]) AS manager
}
}
RETURN n.name AS name, ageGroup, manager
返回 Bob 是因为他是图中唯一拥有更年长经理的人。
| 名称 (name) | ageGroup | manager |
|---|---|---|
|
|
|
行:1 |
||
EXISTS、COLLECT 和 COUNT 子查询的语法[<outerExpression>]
EXISTS|COUNT|COLLECT {
WHEN predicate THEN [{]
<conditionalQuery>
[}]
[WHEN ...]*
[ELSE [{]
<conditionalQuery>
[}]]
}
[<outerExpression>]
EXISTS 子查询在此示例中,WHEN 用于 EXISTS 子查询内部,以根据谓词 (n.age > 40) 的评估结果有条件地执行不同分支。
与 CALL 子查询不同,EXISTS 子查询中返回的变量在外部作用域中不可用(COUNT 和 COLLECT 子查询也是如此)。 |
EXISTS 子查询中的 WHENMATCH (n:Person)
WHERE EXISTS {
WHEN n.age > 40 THEN {
RETURN n.name AS x
}
ELSE {
MATCH (n)-[:LOVES]->(x:Person)
RETURN x
}
}
RETURN n.name AS name,
n.age AS age
Alice 和 Charlie 都大于 40 岁,因此他们由 WHEN 分支返回,而 Bob 则由 ELSE 分支返回。请注意,图中的一些 Person 节点在条件子查询的任何分支中都没有被匹配到,因此不会被返回。
| 名称 (name) | age |
|---|---|
|
|
|
|
|
|
行:3 |
|
将条件查询与 UNION 结合使用
多个条件查询的结果也可以使用 UNION [DISTINCT] 或 UNION ALL 进行组合;前者会从结果集中删除重复项,后者则不会(有关更多信息,请参阅 组合查询 (UNION))。
如果条件查询以 WHEN 开头并涉及 UNION,则 WHEN 分支必须括在花括号 {} 中(相同的 {} 也可用于组合 UNION 和 UNION ALL)。
{} 组合独立 WHEN 分支与 UNION 的语法{
WHEN predicate THEN [{]
<conditionalQuery>
[}]
[WHEN ...]*
[ELSE [{]
<conditionalQuery>
[}]]
}
UNION [DISTINCT|ALL]
{
WHEN predicate THEN [{]
<conditionalQuery>
[}]
[WHEN ...]*
[ELSE [{]
<conditionalQuery>
[}]]
}
[UNION [DISTINCT|ALL] ...]*
{} 组合带有 UNION 的条件分支{
WHEN true THEN RETURN 1 AS x
WHEN false THEN RETURN 2 AS x
ELSE RETURN 3 AS x
}
UNION
{
WHEN false THEN RETURN 4 AS x
WHEN false THEN RETURN 5 AS x
ELSE RETURN 6 AS x
}
| x |
|---|
|
|
行:2 |
如果通过 UNION 组合的查询不是以 WHEN 分支开头的,则不需要花括号。
UNION 结合使用在下面的示例中,UNION 用于组合两个条件子查询的结果(包含整个查询的第一个 CALL 是必需的,以便为每个 person 从每个条件子查询部分收集最终结果)。
该查询根据两个条件对人员进行分类:他们是否拥有 LOVES 关系以及他们是否小于或大于 40 岁。最终结果为每个 person 提供了一个 status 消息列表,显示了两个条件组合后的结果。
UNION 结合使用MATCH (n:Person)
CALL (n) {
OPTIONAL MATCH (n)-[r:LOVES]->(m:Person)
CALL (*) {
WHEN r IS NULL THEN {
RETURN n.name AS person, "Loves no one" AS message
}
ELSE {
RETURN n.name AS person, "Loves somebody" AS message
}
}
RETURN person, message
UNION
CALL (*) {
WHEN n.age < 40 THEN {
RETURN n.name AS person, "Under 40" AS message
}
ELSE {
RETURN n.name AS person, "40 or older" AS message
}
}
RETURN person, message
}
RETURN person, collect(message) AS status
| person | 状态 (status) |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
行数: 6 |
|