UNION 后处理
Cypher 不允许对 UNION
或 UNION ALL
的结果进行进一步处理,因为联合查询中的所有查询都要求有 RETURN
子句。
以下是一些解决方法。
Neo4j 4.0 中的 UNION 后处理
在 Neo4j 4.0 中,现在可以通过子查询进行 UNION 后处理。
使用示例
CALL {
MATCH (movieOrPerson:Movie) RETURN movieOrPerson
UNION
MATCH (movieOrPerson:Person) RETURN movieOrPerson
}
WITH movieOrPerson
...
这使我们能够继续处理 UNION 子查询的结果。
然而,在 4.0 的初始版本中,只支持非关联子查询,这意味着子查询不能使用来自外部调用的变量。这意味着在一个更复杂的查询中间使用子查询进行 UNION 后处理可能不可行,因为您无法将外部查询中的变量传递到子查询中使用。
在 4.0.x 版本中,关联子查询(更实用,可以使用来自子查询外部的变量)目前仅在使用 Neo4j Fabric 时可用。
4.1+ 版本中的 UNION 后处理增强功能
随着 4.1 版本的发布,CALL 子查询功能已得到增强,允许使用关联子查询。这使我们能够在查询中间在子查询中使用现有变量。
这要求在子查询 CALL 块中将 WITH
用作第一个子句,目的是将变量导入到子查询中。
使用 UNION
或 UNION ALL
时,我们可以为每个联合查询提供类似的导入 WITH
子句
MATCH (m:Movie {title:'The Matrix'})
CALL {
WITH m
MATCH (m)<-[:ACTED_IN]-(p)
RETURN p
UNION
WITH m
MATCH (m)<-[:DIRECTED]-(p)
RETURN p
}
RETURN p.name as name
ORDER BY name ASC
这将正确返回《黑客帝国》中所有演员和导演按字母顺序排序的姓名。
这种导入用法有一些特殊限制,通常不适用于 WITH
的用法
-
您只能包含来自外部查询的变量,不能包含其他变量。+ 您不能在初始的
WITH
中执行计算、聚合或引入新变量。 -
您不能在此初始
WITH
中对任何变量进行别名。 -
您不能在初始
WITH
之后使用WHERE
子句进行过滤。
如果您尝试这些操作中的任何一个,将会遇到某种错误,例如
Importing WITH should consist only of simple references to outside variables. Aliasing or expressions are not supported.
或者更隐晦地,如果您尝试在初始 WITH
之后使用 WHERE
子句
Variable `x` not defined
(其中变量是 WITH
子句中存在的第一个)
您可以通过在导入 WITH
之后简单地引入一个额外的 WITH
子句来绕过所有这些限制,如下所示
MATCH (m:Movie)
WHERE m.title CONTAINS 'Matrix'
CALL {
WITH m
WITH m as movie
MATCH (m)<-[:DIRECTED]-(p)
RETURN p.name as name
UNION
WITH m
WITH m
WHERE m.title CONTAINS 'Reloaded'
MATCH (m)<-[:ACTED_IN]-(p)
RETURN p.name as name
}
RETURN DISTINCT name
ORDER BY name ASC
这演示了对导入变量进行别名和过滤的能力,前提是我们使用第二个 WITH
子句,该子句不像用于导入到子查询中的初始 WITH
那样受到相同的限制。
对于更早的版本,不支持原生子查询,因此必须使用其他解决方法。
合并集合,然后 UNWIND
回到行并应用 DISTINCT
MATCH (m:Movie)
WITH collect(m) AS movies
MATCH (p:Person)
WITH movies + collect(p) AS moviesAndPeople
UNWIND moviesAndPeople AS movieOrPerson
WITH DISTINCT movieOrPerson
...
在上述查询中,DISTINCT
并非真正需要,但如果一个结果可能存在于多个合并的集合中,并且您想要唯一值,则需要它。
使用 apoc.cypher.run() 从子查询返回 UNION
结果
使用 APOC 过程,您可以使用 apoc.cypher.run()
在子查询中执行 UNION
,并返回其结果。
CALL apoc.cypher.run('
MATCH (movieOrPerson:Movie)
RETURN movieOrPerson
UNION
MATCH (movieOrPerson:Person)
RETURN movieOrPerson',
{}) yield value
WITH value.movieOrPerson as movieOrPerson
...
请记住,过程调用是按行执行的,因此当多行已存在时使用此方法可能会导致意外和不可预知的结果。
此页面有帮助吗?