如何使 CREATE UNIQUE 与子查询一起使用?
题
我有一个这样的查询:
MATCH left, right
WHERE (ID(right) IN [1, 2, 3] AND ID(left) IN [4, 5, 6])
WITH left, right
LIMIT 1
RETURN left, right
UNION MATCH left, right
WHERE (ID(right) IN [1, 2, 3] AND ID(left) IN [4, 5, 6])
WITH left, right
SKIP 4 LIMIT 1
RETURN left, right
UNION MATCH left, right
WHERE (ID(right) IN [1, 2, 3] AND ID(left) IN [4, 5, 6])
WITH left, right
SKIP 8 LIMIT 1
RETURN left, right
CREATE UNIQUE left-[rel:FRIEND]->right
RETURN rel;
一般来说,我只是创建一个数据集,以便稍后在 CREATE UNIQUE 指令中使用它。
显然,这不起作用 - 查询分析器说我只能使用 RETURN 子句一次。我的问题是 - 在这种情况下如何组成数据集?我尝试分配一个别名并在 CREATE UNIQUE 中使用它 - 也无法让它工作。我究竟做错了什么?这种情况有可能吗?
解决方案
我可能会误解您的需求,但是当我查看您的查询时,我会想到以下内容。
首先,这是对您的查询的改编,使用 SKIP
和 LIMIT
没有 RETURN
或者 UNION
.
MATCH left, right
WHERE ID(left) IN [1,2,3] AND ID(right) IN [4,5,6]
WITH left, right
LIMIT 1
CREATE UNIQUE left-[rel:FRIEND]->right
WITH [rel] as rels //If you want to return the relationship later you can put it in a collection and bring it WITH
MATCH left, right
WHERE ID(left) IN [1,2,3] AND ID(right) IN [4,5,6]
WITH left, right, rels
SKIP 4 LIMIT 1
CREATE UNIQUE left-[rel:FRIEND]->right
WITH rels + [rel] as rels
MATCH left, right
WHERE ID(left) IN [1,2,3] AND ID(right) IN [4,5,6]
WITH left, right, rels
SKIP 8 LIMIT 1
CREATE UNIQUE left-[rel:FRIEND]->right
WITH rels + [rel] as rels
RETURN LENGTH(rels), rels // You can return the relationships here but SKIP/LIMIT does its job also if you don't return anything
但这个查询有点疯狂。这实际上是三个查询,其中两个查询被人为地挤入作为第一个查询的子查询。它在每个子查询中重新匹配相同的节点,并且通过这种方式运行查询而不是单独运行查询实际上没有任何收获(它实际上更慢,因为在每个子查询中您还匹配您知道不会使用的节点) 。
所以我的第一个建议是使用 START
代替 MATCH...WHERE
通过 id 获取节点时。按照目前的情况,查询将数据库中的每个节点绑定为“左”,然后将数据库中的每个节点绑定为“右”,然后过滤掉绑定到“左”的所有不符合条件的节点这 WHERE
子句,然后“正确”也是如此。由于这部分查询重复了3次,因此数据库中的所有节点总共被绑定了6次。这对于建立三种关系来说是昂贵的。如果你使用 START
您可以立即绑定您想要的节点。这并不能真正回答你的问题,但它会更快并且查询会更干净。所以,使用 START
通过内部 id 获取节点。
START left = node(1,2,3), right = node(4,5,6)
我想到的第二件事是匹配模式时节点和“路径”或“结果项”之间的区别。当您绑定“左”中的三个节点和“右”中的其他三个节点时,您不会得到三个结果项,而是九个。对于“左”绑定的每个节点,您会得到三个结果,因为有三个可能的“右”可以将其组合。如果您想将每个“左”与每个“右”联系起来,那就太好了。但我认为你正在寻找的是结果项 (1),(4)
, (2),(5)
, (3),(6)
, ,虽然在一个查询中将三个“左”节点和三个“右”节点与节点 id 集合绑定起来似乎很方便,但是您必须执行所有过滤操作才能删除 6 个不需要的匹配项。查询变得复杂且麻烦,并且实际上比单独运行查询要慢。另一种说法是 (1)-[:FRIEND]->(4)
是一个独特的模式,与您正在创建的其他模式没有(相关)连接。如果你想创建的话,情况会有所不同 (1)-[:FRIEND]->(2)<-[:FRIEND]-(3)
, ,那么您需要一起处理这三个节点。也许您只是在探索密码的边缘用途,但我认为我应该指出这一点。顺便说一下,使用 SKIP
和 LIMIT
这种方式有点跑调,它们并不是真正用于模式匹配和过滤。它也是不可预测的,除非你也使用 ORDER BY
, ,因为不能保证结果将按一定顺序排列。您不知道 get 传递的是哪个结果项。无论如何,在这种情况下,我认为最好绑定节点并在三个单独的查询中创建关系。
START left = node(1), right = node(4)
CREATE UNIQUE left-[rel:FRIEND]->right
RETURN rel
START left = node(2), right = node(5)
CREATE UNIQUE left-[rel:FRIEND]->right
RETURN rel
START left = node(3), right = node(6)
CREATE UNIQUE left-[rel:FRIEND]->right
RETURN rel
因为你已经知道你想要那三对,而不是说, (1),(4)
,(1),(5)
,(1),(6)
仅查询这些对是有意义的,最简单的方法是单独查询。
但 第三, ,由于这三个查询在结构上是相同的,仅属性值不同(如果 id 被视为属性),您可以通过概括或匿名化区分它们的内容来简化查询,即使用参数。
START left = node({leftId}), right = node({rightId})
CREATE UNIQUE left-[rel:FRIEND]->right
RETURN rel
parameters: {leftId:1, rightId:4}, {leftId:2, rightId:5}, {leftId:3, rightId:6}
由于结构相同,cypher 可以缓存执行计划。这带来了良好的性能,并且查询整洁、可维护,并且如果以后您想在其他节点对上执行相同的操作,则可以轻松扩展。