UNION 后处理
Cypher 不允许对 UNION 或 UNION ALL 的结果进行进一步处理,因为在 union 的所有查询中都必须使用 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 子句不像用于导入到子查询的初始 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
...
请记住,过程调用是按行执行的,因此在已有多行时使用此方法可能导致意外和不可预料的结果。
此页面有帮助吗?