条件表达式 (CASE)

通用条件表达式可以在 Cypher® 中使用 CASE 结构来表达。Cypher 中存在两种 CASE 变体:简单形式,用于将单个表达式与多个值进行比较,以及通用形式,用于表达多个条件语句。

如果你想在后续子句中使用结果,CASE 只能用作 RETURNWITH 的一部分。

示例图

以下图用于下面的示例

case graph

要重新创建该图,请在空的 Neo4j 数据库上运行以下查询

CREATE
  (alice:Person {name:'Alice', age: 38, eyes: 'brown'}),
  (bob:Person {name: 'Bob', age: 25, eyes: 'blue'}),
  (charlie:Person {name: 'Charlie', age: 53, eyes: 'green'}),
  (daniel:Person {name: 'Daniel', eyes: 'brown'}),
  (eskil:Person {name: 'Eskil', age: 41, eyes: 'blue'}),
  (alice)-[:KNOWS]->(bob),
  (alice)-[:KNOWS]->(charlie),
  (bob)-[:KNOWS]->(daniel),
  (charlie)-[:KNOWS]->(daniel),
  (bob)-[:MARRIED]->(eskil)

简单 CASE

简单 CASE 形式用于将单个表达式与多个值进行比较,类似于编程语言的 switch 结构。通过 WHEN 运算符评估表达式,直到找到匹配项。如果未找到匹配项,则返回 ELSE 运算符中的表达式。如果没有 ELSE 情况且未找到匹配项,则将返回 null

语法

CASE test
  WHEN value [, value]* THEN result
  [WHEN ...]
  [ELSE default]
END

参数

名称 描述

test

一个表达式。

value

一个表达式,其结果将与 test 进行比较。

result

如果 valuetest 匹配,则返回的表达式作为输出

default

如果没有任何值与测试表达式匹配,则要返回的表达式。

示例

MATCH (n:Person)
RETURN
CASE n.eyes
  WHEN 'blue'  THEN 1
  WHEN 'brown', 'hazel' THEN 2
  ELSE 3
END AS result, n.eyes
result n.eyes

2

"棕色"

1

"蓝色"

3

"绿色"

2

"棕色"

1

"蓝色"

行数:5

扩展简单 CASE

扩展简单 CASE 形式允许显式指定比较运算符。简单 CASE 使用隐式等于 (=) 比较器。

支持的比较器是

语法

CASE test
  WHEN [comparisonOperator] value [, [comparisonOperator] value ]* THEN result
  [WHEN ...]
  [ELSE default]
END

参数

名称 描述

test

一个表达式。

comparisonOperator

支持的比较运算符之一。

value

一个表达式,其结果使用给定的比较运算符与 test 进行比较。

result

如果 valuetest 匹配,则返回的表达式作为输出。

default

如果没有任何值与测试表达式匹配,则要返回的表达式。

示例

MATCH (n:Person)
RETURN n.name,
CASE n.age
  WHEN IS NULL, IS NOT TYPED INTEGER | FLOAT THEN "Unknown"
  WHEN = 0, = 1, = 2 THEN "Baby"
  WHEN <= 13 THEN "Child"
  WHEN < 20 THEN "Teenager"
  WHEN < 30 THEN "Young Adult"
  WHEN > 1000 THEN "Immortal"
  ELSE "Adult"
END AS result
n.name result

"爱丽丝"

"成年人"

"鲍勃"

"青年人"

"查理"

"成年人"

"丹尼尔"

"未知"

"埃斯基尔"

"成年人"

行数:5

通用 CASE

通用 CASE 表达式支持多个条件语句,类似于编程语言的 if-elseif-else 结构。每个行按顺序评估,直到找到一个 true 值。如果未找到匹配项,则返回 ELSE 运算符中的表达式。如果没有 ELSE 情况且未找到匹配项,则将返回 null

语法

CASE
  WHEN predicate THEN result
  [WHEN ...]
  [ELSE default]
END

参数

名称 描述

predicate

谓词是一个表达式,它计算为一个 BOOLEAN 值。在这种情况下,谓词被测试以找到一个有效的备选方案。

result

如果 predicate 计算为 true,则返回的表达式作为输出。

default

如果没有找到匹配项,则返回 default

示例

MATCH (n:Person)
RETURN
CASE
  WHEN n.eyes = 'blue' THEN 1
  WHEN n.age < 40      THEN 2
  ELSE 3
END AS result, n.eyes, n.age
result n.eyes n.age

2

"棕色"

38

1

"蓝色"

25

3

"绿色"

53

3

"棕色"

null

1

"蓝色"

41

行数:5

带有 null 值的 CASE

在使用 null 值时,你可能被迫使用通用 CASE 形式。以下两个示例使用 Daniel 节点的 age 属性(该属性的 age 值为 null)来阐明差异。

简单 CASE
MATCH (n:Person)
RETURN n.name,
CASE n.age  (1)
  WHEN null THEN -1  (2)
  ELSE n.age - 10 (3)
END AS age_10_years_ago
1 n.age 是正在评估的表达式。请注意,节点 Danielage 值为 null
2 此分支被跳过,因为 null 不等于任何其他值,包括 null 本身。
3 执行进入 ELSE 分支,它输出 null,因为 n.age - 10 等于 null
n.name age_10_years_ago

"爱丽丝"

28

"鲍勃"

15

"查理"

43

"丹尼尔"

null

"埃斯基尔"

31

行数:5

通用 CASE
MATCH (n:Person)
RETURN n.name,
CASE  (1)
  WHEN n.age IS NULL THEN -1  (2)
  ELSE n.age - 10
END AS age_10_years_ago
1 如果没有在 CASE 后提供表达式,它将以通用形式运行,支持每个分支中的谓词表达式。
2 此谓词表达式对于节点 Daniel 计算为 true,因此返回此分支的结果。
n.name age_10_years_ago

"爱丽丝"

28

"鲍勃"

15

"查理"

43

"丹尼尔"

-1

"埃斯基尔"

31

行数:5

有关 null 的更多信息,请参阅 使用 null

CASE 表达式和后续子句

CASE 表达式的结果可用于设置节点或关系上的属性。

MATCH (n:Person)
WITH n,
CASE n.eyes
  WHEN 'blue'  THEN 1
  WHEN 'brown' THEN 2
  ELSE 3
END AS colorCode
SET n.colorCode = colorCode
RETURN n.name, n.colorCode
n.name n.colorCode

"爱丽丝"

2

"鲍勃"

1

"查理"

3

"丹尼尔"

2

"埃斯基尔"

1

行数:5

有关使用 SET 子句的更多信息,请参阅 SET

其他注意事项

CASE 结果分支在执行之前会进行静态检查。这意味着,如果一个分支在语义上不正确,它仍然会抛出一个异常,即使该分支可能在运行时永远不会被执行。

在以下示例中,date 静态地知道是一个 STRING 值,因此如果将其视为 DATE 值,则会失败。

不允许
WITH "2024-08-05" AS date, "string" AS type
RETURN CASE type
    WHEN "string" THEN datetime(date)
    WHEN "date" THEN datetime({year: date.year, month: date.month, day: date.day})
    ELSE datetime(date)
END AS dateTime
错误消息
Type mismatch: expected Map, Node, Relationship, Point, Duration, Date, Time, LocalTime, LocalDateTime or DateTime but was String (line 4, column 38 (offset: 136))
"    WHEN 'date' THEN datetime({year: date.year, month: date.month, day: date.day})"
                                      ^