子句组合
本节描述在组合不同的读写子句时,Cypher® 的语义。
一个查询由多个子句链接在一起组成。这些子句将在 子句 章中更详细地讨论。
整个查询的语义由其子句的语义定义。每个子句以图的状态和由当前变量组成的中间结果表作为输入。子句的输出是一个新的图状态和一个新的中间结果表,作为下一个子句的输入。第一个子句以查询前的图状态和一个空的中间结果表作为输入。最后一个子句的输出是查询的结果。
除非使用 ORDER BY,否则 Neo4j 不保证查询结果的行顺序。 |
本节中将使用以下示例图。
以下是以下查询每个子句后的中间结果表和图状态:
MATCH (john:Person {name: 'John'})
MATCH (john)-[:FRIEND]->(friend)
RETURN friend.name AS friendName
此查询只有读子句,因此图状态保持不变,因此在下面省略。
子句 | 子句后的中间结果表 | ||||||
---|---|---|---|---|---|---|---|
MATCH (john:Person {name: 'John'}) |
|
||||||
MATCH (john)-[:FRIEND]->(friend) |
|
||||||
RETURN friend.name AS friendName |
|
以上示例只查看了允许线性组合的子句,并省略了写子句。下一节将探讨这些非线性组合和写子句。
读写查询
在 Cypher 查询中,读写子句可以轮流执行。读写查询最重要的方面是图的状态也会在子句之间发生变化。
子句永远无法观察到后面子句所做的写操作。 |
使用与上面相同的示例图,此示例显示以下查询每个子句后的中间结果表和图状态:
MATCH (j:Person) WHERE j.name STARTS WITH "J"
CREATE (j)-[:FRIEND]->(jj:Person {name: "Jay-jay"})
此查询找到所有 name
属性以 "J" 开头的节点,并为每个这样的节点创建一个 name
属性设置为 "Jay-jay" 的新节点。
子句 | 子句后的中间结果表 | 子句后的图状态,变化以红色显示 | ||||||
---|---|---|---|---|---|---|---|---|
MATCH (j:Person) WHERE j.name STARTS WITH "J" |
|
|||||||
CREATE (j)-[:FRIEND]->(jj:Person {name: "Jay-jay"}) |
|
重要的是要注意,MATCH
子句不会找到由 CREATE
子句创建的 Person
节点,即使名称 "Jay-jay" 以 "J" 开头。这是因为 CREATE
子句在 MATCH
子句之后,因此 MATCH
无法观察到 CREATE
所做的对图的任何更改。
使用 UNION
的查询
UNION
查询略有不同,因为两个或多个查询的结果被组合在一起,但每个查询都以一个空的中间结果表开始。
在使用 UNION
子句的查询中,UNION
之前的任何子句都无法观察到 UNION
之后的子句所做的写操作。UNION
之后的任何子句都可以观察到 UNION
之前的子句所做的所有写操作。这意味着子句永远无法观察到后面子句所做的写操作的规则,在使用 UNION
的查询中仍然适用。
UNION
的查询中的中间结果表和图状态使用与上面相同的示例图,此示例显示以下查询每个子句后的中间结果表和图状态:
CREATE (jj:Person {name: "Jay-jay"})
RETURN count(*) AS count
UNION
MATCH (j:Person) WHERE j.name STARTS WITH "J"
RETURN count(*) AS count
子句 | 子句后的中间结果表 | 子句后的图状态,变化以红色显示 | ||||
---|---|---|---|---|---|---|
CREATE (jj:Person {name: "Jay-jay"}) |
|
|||||
RETURN count(*) AS count |
|
|||||
MATCH (j:Person) WHERE j.name STARTS WITH "J" |
|
|||||
RETURN count(*) AS count |
|
重要的是要注意,MATCH
子句找到了由 CREATE
子句创建的 Person
节点。这是因为 CREATE
子句在 MATCH
子句之前,因此 MATCH
可以观察到 CREATE
所做的对图的任何更改。
使用 CALL {}
子查询的查询
在 CALL {}
子句中的子查询是针对每个传入的输入行进行评估的。这意味着子查询中的写子句可能会执行多次。子查询的不同调用按顺序依次执行,即按照传入输入行的顺序执行。
子查询的后续调用可以观察到子查询之前调用所做的写操作。
CALL {}
的查询中的中间结果表和图状态使用与上面相同的示例图,此示例显示以下查询每个子句后的中间结果表和图状态:
以下查询使用 变量作用域子句(在 Neo4j 5.23 中引入)将变量导入 CALL 子查询。如果您使用的是旧版本的 Neo4j,请改用 导入 WITH 子句。 |
MATCH (john:Person {name: 'John'})
SET john.friends = []
WITH john
MATCH (john)-[:FRIEND]->(friend)
WITH john, friend
CALL (john, friend) {
WITH john.friends AS friends
SET john.friends = friends + friend.name
}
子句 | 子句后的中间结果表 | 子句后的图状态,变化以红色显示 | ||||||
---|---|---|---|---|---|---|---|---|
MATCH (john:Person {name: 'John'}) |
|
|||||||
SET john.friends = [] |
|
|||||||
MATCH (john)-[:FRIEND]->(friend) |
|
|||||||
第一次调用 WITH john.friends AS friends |
|
|||||||
第一次调用 SET john.friends = friends + friend.name |
|
|||||||
第二次调用 WITH john.friends AS friends |
|
|||||||
第二次调用 SET john.friends = friends + friend.name |
|
需要注意的是,在子查询中,WITH
子句的第二次调用可以观察到 SET
子句的第一次调用所做的写入操作。