知识库

UNION 后处理

Cypher 不允许对 UNIONUNION 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,以便将变量导入到子查询中。

在使用 UNIONUNION 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 的使用。

  1. 您只能包含来自外部查询的变量,不能包含其他变量。+ 在初始的 WITH 中不能进行计算、聚合或引入新变量。

  2. 您不能在初始的 WITH 中对任何变量进行别名处理。

  3. 您不能在初始的 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 那样受到限制。

适用于 3.5.x 及更早版本

对于早期版本,不支持本机子查询,因此必须使用其他变通方法。

合并集合,然后 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
...

请记住,过程调用是按行执行的,因此在已有多行时使用此方法可能导致意外和不可预料的结果。

© . This site is unofficial and not affiliated with Neo4j, Inc.