EXISTS 子查询

EXISTS 子查询可以用于确定指定的模式在图中是否存在至少一次。它与路径模式的功能相同,但功能更强大,因为它允许在内部使用 MATCHWHERE 子句。

示例图

以下图用于下面的示例

subqueries graph

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

CREATE
(andy:Swedish:Person {name: 'Andy', age: 36}),
(timothy:Person {name: 'Timothy', nickname: 'Tim', age: 25}),
(peter:Person {name: 'Peter', nickname: 'Pete', age: 35}),
(andy)-[:HAS_DOG {since: 2016}]->(:Dog {name:'Andy'}),
(timothy)-[:HAS_CAT {since: 2019}]->(:Cat {name:'Mittens'}),
(fido:Dog {name:'Fido'})<-[:HAS_DOG {since: 2010}]-(peter)-[:HAS_DOG {since: 2018}]->(:Dog {name:'Ozzy'}),
(fido)-[:HAS_TOY]->(:Toy{name:'Banana'})

简单的 EXISTS 子查询

外部范围引入的变量可以在 EXISTS 子查询中使用,无需导入。在这方面,EXISTS 子查询与 CALL 子查询不同,后者需要导入。以下示例展示了这一点

MATCH (person:Person)
WHERE EXISTS {
    (person)-[:HAS_DOG]->(:Dog)
}
RETURN person.name AS name
name

"Andy"

"Peter"

行数:2

带有 WHERE 子句的 EXISTS 子查询

可以与 MATCH 结合使用 WHERE 子句。MATCH 子句和外部范围引入的变量可以在此范围中使用。

MATCH (person:Person)
WHERE EXISTS {
  MATCH (person)-[:HAS_DOG]->(dog:Dog)
  WHERE person.name = dog.name
}
RETURN person.name AS name
name

"Andy"

行数:1

嵌套 EXISTS 子查询

EXISTS 子查询可以像下面的示例展示的那样嵌套。嵌套还会影响范围。这意味着可以访问子查询内部的所有变量,这些变量可以来自外部范围,也可以在同一个子查询中定义。

MATCH (person:Person)
WHERE EXISTS {
  MATCH (person)-[:HAS_DOG]->(dog:Dog)
  WHERE EXISTS {
    MATCH (dog)-[:HAS_TOY]->(toy:Toy)
    WHERE toy.name = 'Banana'
  }
}
RETURN person.name AS name
name

"Peter"

行数:1

WHERE 子句外部的 EXISTS 子查询

EXISTS 子查询表达式可以出现在任何表达式有效的范围内。这里结果是一个布尔值,表示子查询是否可以找到给定模式。

MATCH (person:Person)
RETURN person.name AS name, EXISTS {
  MATCH (person)-[:HAS_DOG]->(:Dog)
} AS hasDog
name hasDog

"Andy"

true

"Timothy"

false

"Peter"

true

行数:3

带有 UNIONEXISTS 子查询

Exists 可以与 UNION 子句一起使用,并且不需要 RETURN 子句。值得注意的是,如果一个分支具有 RETURN 子句,则所有分支都需要一个。以下示例说明,如果其中一个 UNION 分支要返回至少一行,则整个 EXISTS 表达式将评估为 true。

MATCH (person:Person)
RETURN
    person.name AS name,
    EXISTS {
        MATCH (person)-[:HAS_DOG]->(:Dog)
        UNION
        MATCH (person)-[:HAS_CAT]->(:Cat)
    } AS hasPet
name hasPet

"Andy"

true

"Timothy"

true

"Peter"

true

行数:3

带有 WITHEXISTS 子查询

外部范围的变量对于整个子查询是可见的,即使使用 WITH 子句也是如此。为了避免混淆,不允许对这些变量进行遮蔽。当内部范围中新引入的变量使用相同变量定义时,外部范围变量就会被遮蔽。在下面的示例中,外部变量 name 被遮蔽,因此会引发错误。

WITH 'Peter' as name
MATCH (person:Person {name: name})
WHERE EXISTS {
    WITH "Ozzy" AS name
    MATCH (person)-[:HAS_DOG]->(d:Dog)
    WHERE d.name = name
}
RETURN person.name AS name
错误消息
The variable `name` is shadowing a variable with the same name from the outer scope and needs to be renamed (line 4, column 20 (offset: 90))

可以将新变量引入子查询,只要它们使用不同的标识符即可。在下面的示例中,WITH 子句引入了一个新变量。请注意,主查询中引用的外部范围变量 personWITH 子句之后仍然可用。

MATCH (person:Person)
WHERE EXISTS {
    WITH "Ozzy" AS dogName
    MATCH (person)-[:HAS_DOG]->(d:Dog)
    WHERE d.name = dogName
}
RETURN person.name AS name
name

"Peter"

行数:1

带有 RETURNEXISTS 子查询

EXISTS 子查询不需要在子查询末尾使用 RETURN 子句。如果存在,则不需要将其别名,这与 CALL 子查询 不同。EXISTS 子查询中返回的任何变量在子查询之后都不可用。

MATCH (person:Person)
WHERE EXISTS {
    MATCH (person)-[:HAS_DOG]->(:Dog)
    RETURN person.name
}
RETURN person.name AS name
name

"Andy"

"Peter"

行数:2

规则

以下内容适用于 EXISTS 子查询

  • 允许使用任何非写入查询。

  • 如果 EXISTS 子查询评估为至少一行,则整个表达式将变为 true。这也意味着系统只需要评估是否存在至少一行,并且可以跳过其余工作。

  • EXISTS 子查询与普通查询的不同之处在于,可以省略最终的 RETURN 子句,因为子查询中定义的任何变量在表达式外部都不可用,即使使用了最终的 RETURN 子句也是如此。

  • 在子查询中,如果EXISTS语句仅包含一个模式和一个可选的WHERE子句,则可以省略MATCH关键字。

  • EXISTS子查询可以出现在查询中任何表达式有效的的位置。

  • 在外部作用域定义的任何变量都可以在子查询的内部作用域中引用。

  • 在子查询内部引入的变量不属于外部作用域,因此无法在外部访问。