[图片1 ][1]
根据查询2个关系的顺序,尽管查询相同(据我了解),我还是会得到2个不同的答案。该查询显然是不同的,但我不知道为什么。
MATCH p1=(:Barrier {code: 'B2'})-[:REL1]->()
WITH count(DISTINCT p1) AS failed_B2
MATCH p2=(:Barrier {code: 'B2'})-[:REL2]->()
RETURN count(DISTINCT p2) AS worked_B2, failed_B2
返回1和0-正确
但反过来:
MATCH p1=(:Barrier {code: 'B2'})-[:REL2]->()
WITH count(DISTINCT p1) AS failed_B2
MATCH p2=(:Barrier {code: 'B2'})-[:REL1]->()
RETURN count(DISTINCT p2) AS worked_B2, failed_B2
返回0和0-这是不正确的
我想合并多个查询的结果,但是UNION无法正常工作,因为它需要将结果分组在同一列下,在我看来这是不正确的。我需要将结果放在不同的列中。
答案 0 :(得分:0)
所以这是一件有趣的事情,它围绕着当行被过滤掉(例如当MATCH失败或WHERE条件过滤行)时发生的事情。
但是首先我们需要解决您在第二种情况下观察到的问题:Returns 0 and 0
。我不认为这是真的,我想知道您在这里使用的是什么版本的Neo4j。在这种情况下,我本来希望没有返回任何行,而这与返回两者都具有0值的行完全不同。
执行Cypher查询时,它们会建立数据记录(或行)。 Cypher操作每行执行一次。因此,当您在查询中的某个点执行MATCH时,将按行执行,而当MATCH失败时,如果不存在这种模式(该模式遵循WHERE子句,如果存在的话),则会将该行过滤掉。这很重要,因为这意味着该记录中的所有其他数据都已消失并且不再可寻址。
要记住的第二件事是,即使没有行存在,我们也允许某些聚合,例如count()
和collect()
执行 ,因为可以想到您可能有一个查询,没有任何匹配项,并且将该计数设为0(或在收集时为空集合)是完全有效的情况,应该允许。在这些情况下,在MATCH或过滤器之后可能根本没有剩余的行(并且由于没有行,所以将无法执行其他任何操作,因为Cypher操作每行执行一次,因此如果有,则没有操作)没有行),则count()
或collect()
会导致出现一个新的行,其计数为0或为空集合。并且由于现在存在一行,因此查询中其余的运算符可以执行一些操作,并且查询可以继续执行。
这是在您的第一种情况下发生的情况,其中模式p1
不存在,而模式p2
存在(一次)。这是发生的情况的细分:
count()
聚合(作用域中没有其他变量,这很重要)。这会发出一个单行,计数为0,这是正确的:在图形中没有该模式的出现。{failed_B2:0}
),它找到了单个匹配项,并获得了计数(1),并且能够输出期望的答案(1、0),其中1是查询末尾的模式匹配数p2,而0是查询的前两行的模式匹配数p1 。现在让我们看看当我们扭转这种情况时会发生什么。
在第二个查询中,现在模式p1
在图中存在一次,而模式p2
不存在。这是发生的故障:
{failed_B2:1}
failed_B2
值可供参考。p2
和failed_B2
的计数。但这是Cypher所不允许的,当它是独立的count()或collect()时,我们只允许跨0行聚合,没有failed_B2
引用,当包含的记录/行被擦除时它被过滤掉了。无法合理地进行处理,因为以前不存在现有数据(这是正确的行为)。查询应该不返回任何行...与0, 0
不同,因为这意味着您返回了一行(这就是为什么我有兴趣用您)。关于应该如何正确执行此操作,当您必须像这样进行聚合并且知道某些模式可能不存在时,请改用OPTIONAL MATCH。
当您选择匹配时,如果找不到匹配项,则不会过滤掉该行。相反,模式中新引入的变量将变为null,并且当您对null进行count()或collect()时,它将忽略它们,从而使您的计数正确为0,但不会清除包含{{1的记录/行}}值,您也想在最后返回。