您得到意外结果的原因是 WHERE 子句的位置和含义,以及它与 OPTIONAL MATCH 行为的交互。
WHERE 仅适用于前面的 MATCH、OPTIONAL MATCH 或 WITH。在这种情况下,它并不适用于查询的所有结果,它仅适用于 OPTIONAL MATCH,这与您所期望的行为完全不同。
如果您将其隔离并单独查看 OPTIONAL MATCH 和 WHERE 会有所帮助:
OPTIONAL MATCH (p) -[r]- (m:Movie)
Where type(r) = null
这意味着:可选地通过关系 r 从 p 匹配到 a :Movie m,其中 r 为空。你不能有一个存在但它的类型为空的关系,这是不可能的,所以这个 OPTIONAL MATCH 总是会失败。
但是因为它是一个 OPTIONAL MATCH,所以不会删除行,而是不匹配的元素将为 null。结果是带有 :Person p 的行(来自您之前的匹配),并且 type(r) 和 m 为 null。
您实际上想要的是首先执行可选匹配,然后过滤掉类型为空的行。您需要一个影响查询所有行的 WHERE,而不是 OPTIONAL MATCH。
这需要我们添加一个 WITH 子句,并将 WHERE 移到它后面:
MATCH (p:Person)
OPTIONAL MATCH (p) -[r]- (m:Movie)
WITH p, r, m
Where type(r) = null
Return p, type(r), m
将 WHERE 从 OPTIONAL MATCH 移动到 WITH 改变了它的含义,它现在将应用于查询的所有行,并且由于它不再与 OPTIONAL MATCH 关联,它实际上会删除不适合的行谓词而不是保留行并将元素设置为空。
现在,说了这么多,有一个更简单的查询来返回你想要的,根本不使用 OPTIONAL MATCH:
MATCH (p:Person)
WHERE NOT (p)--(:Movie)
RETURN p
匹配 :Person 节点,从这些 :Persons 到 :Movie 节点没有关系。
我们可以省略返回关系类型和电影节点,因为根据您的匹配,它们将不存在。