为什么我的 WHERE 子句不起作用?
当 WHERE 子句似乎不起作用时,这会令人沮丧。可以使用以下方法来找出问题所在。
检查 OPTIONAL MATCH 后的 WHERE 子句
WHERE 子句不能单独使用,它们总是与 MATCH、WITH 或 OPTIONAL MATCH 配对,并且正是这种配对决定了当 WHERE 子句的结果为 false 时的行为。
WITH … WHERE 和 MATCH … WHERE 会将 WHERE 子句应用于所有结果行,这通常也是大多数用户期望的 WHERE 行为——当 WHERE 为 false 时删除对应的行。
然而,OPTIONAL MATCH … WHERE 的行为不同,因为 OPTIONAL MATCH 永远不会删除行。使用 OPTIONAL MATCH 时,如果给定的模式不匹配,或其 WHERE 子句的结果为 false,则该模式中新引入的变量在当前行上会变为 null。行永远不会被删除,已有的变量保持不变,这会给人一种 WHERE 子句根本没有起作用的错觉,实际问题在于它被错误地应用到了不该应用的地方。
MATCH (m:Movie)
OPTIONAL MATCH (m)<-[:WORKED_ON]-(a:Animator)
WHERE m.releaseYear > 1999 AND a IS NOT NULL
RETURN m, collect(a) as animators
在上面的例子中,看起来像是查询 1999 年以后上映的电影以及这些电影的动画师,但这并不准确。WHERE 子句只会影响 OPTIONAL MATCH,因此所有电影都会被返回,均不会被过滤掉,只是动画师集合只会在 1999 年以后上映的电影上被填充。
要修复该查询,需要把 WHERE 移动到其他位置,使其与 MATCH 或 WITH 关联,从而在需要时过滤掉行。
MATCH (m:Movie)
OPTIONAL MATCH (m)<-[:WORKED_ON]-(a:Animator)
WITH m, a
WHERE m.releaseYear > 1999 AND a IS NOT NULL
RETURN m, collect(a) as animators
检查 WHERE 子句中的拼写错误或大小写不匹配
拼写错误和写错的元素很容易导致 WHERE 子句失效,这其中也包括大小写不匹配。
节点标签、关系类型、变量以及属性键和值都区分大小写,请确保在大小写上保持一致且正确。
MATCH (m:Movie)
WHERE NOT (m)<-[:worked_on]-(a:animator) AND m.ReleaseYear > 1999
RETURN m
上述查询没有拼写错误,但关系类型、节点标签和属性键的大小写与图中实际存储的不一致,这会显著影响 WHERE 子句的效果。
检查假定的数值属性是否实际上是字符串
当数值比较或匹配似乎失效时,最好确认你正在比较的属性确实是数字。
在文本结果视图中,字符串值会带引号,而数值则不会。
导入时要格外留意,尤其是 CSV 导入,因为所有值默认都会被解释为字符串。需要使用 toInteger() 和 toFloat() 将字符串转换为数值,以避免此类问题。
检查属性键和值中的前导或尾随空格
属性中的前导或尾随空格会让 WHERE 子句看起来像是失效了,这通常是图中数据本身的问题,而非查询本身的错误。
MATCH (m:Movie)<-[:ACTED_IN]-(p:Person)
WHERE p.name = 'Keanu Reeves'
RETURN m
上述查询看起来没有问题,甚至可能完全正确。但如果节点的 name 属性实际上是 "Keanu Reeves "(末尾有空格),查询就会失效。
通常建议再次确认节点和关系上预期的字符串值,看看是否有意外的空格。如果使用 Neo4j 浏览器,文本结果视图通常是最方便检测额外空格的方式。使用 STARTS WITH、ENDS WITH 或 CONTAINS 进行查询也能帮助检验属性值的假设。
属性键中的额外空格比较少见,但确实会发生,例如从格式错误的文件导入数据时。
例如,如果我们尝试导入以下标题的 CSV 文件:
nickName, firstName,lastName
在 firstName 前有一些前导空格,在 lastName 后有尾随空格。导入后,属性键本身会包含这些空格,实际的属性键会变成 "nickName"、" firstName" 和 "lastName ",如果没有被发现,就会很快成为混淆的来源。
此页面有帮助吗?