【问题标题】:Neo4j Cypher MATCH if Not exists如果不存在,Neo4j Cypher 匹配
【发布时间】:2017-01-08 09:01:26
【问题描述】:

在 SQL 中,where 是一个选项 (NOT EXISTS),它允许我们仅在其他 SELECT 的结果为零时选择一行。

例如:

SELECT 
    c.CustomerKey
FROM
    Customer c, Sales s1, Date d
WHERE
    s1.CustomerKey = c.CustomerKey AND
    s1.OrderDateKey = d.DateKey AND
    s1.ShipDate > s1.DueDate AND
    NOT EXISTS (SELECT *
                FROM Sales s2
                WHERE s2.OrderDateKey = s1.OrderDateKey AND
                      s2.CustomerKey <> s1.CustomerKey)
GROUP BY 
    c.CustomerKey

我尝试执行以下操作,但查询永远不会结束,所以我认为我做错了。我错过了什么?

MATCH (d1:Date)<-[:ORDERDATE]-(s1:Sales)-[:CUSTOMER]->(c1:Customer)
WHERE s1.ShipDate > s1.DueDate
WITH d1,s1,c1
MATCH (s2:Sales)-[:CUSTOMER]->(c2:Customer)
WHERE NOT(s2.OrderDateKey=s1.OrderDateKey AND c2.CustomerKey<>c1.CustomerKey)
RETURN c2.CustomerKey

【问题讨论】:

  • CustomerKey 是否唯一标识客户?

标签: neo4j cypher


【解决方案1】:

将 SQL 转换为 Cypher 的棘手部分是弄清楚我们何时仍应基于键进行连接和谓词,以及何时应将这些操作转换为节点和关系的使用。

让我们先翻译一下 SQL 的含义,尽我所能:

我们希望将销售与客户和订单日期相匹配,其中 销售的发货日期已超过到期日,并且还没有销售 不同客户的相同订单日期。

看起来 Sale.OrderDateKey 是 Date.DateKey 主键的外键,而 Sales.CustomerKey 是 Customer.CustomerKey 主键的外键。

如果上述假设成立,那么我们根本不需要使用这些键...SQL 使用外键和主键进行连接,Neo4j 使用节点之间的关系,所以我们不需要实际上将这些字段用于此查询中的任何内容,但返回值除外。

MATCH (orderDate:Date)<-[:ORDERDATE]-(s1:Sales)-[:CUSTOMER]->(c1:Customer)
WHERE s1.ShipDate > s1.DueDate
WITH orderDate, c1
// match to exclude is a sale with the same orderDate but different customer
OPTIONAL MATCH (orderDate)<-[:ORDERDATE]-(:Sales)-[:CUSTOMER]->(c2:Customer)
WHERE c1 <> c2
WITH c1
WHERE c2 IS NULL
RETURN DISTINCT c1.customerKey;

【讨论】:

    【解决方案2】:

    下面的查询应该做你想做的事。

    首先,您应该在:Sales(OrderDateKey) 上创建一个索引,以便下面查询中的OPTIONAL MATCH 可以快速找到所需的Sales 节点(而不是扫描所有节点):

    CREATE INDEX ON :Sales(OrderDateKey);
    

    当OPTIONAL MATCH 子句找不到匹配项时,它会将其未绑定的标识符设置为NULL。以下查询利用了这一事实:

    MATCH (:Date)<-[:ORDERDATE]-(s1:Sales)-[:CUSTOMER]->(c1:Customer)
    WHERE s1.ShipDate > s1.DueDate
    WITH s1.OrderDateKey AS odk, c1.CustomerKey AS customerKey
    OPTIONAL MATCH (s2:Sales)-[:CUSTOMER]->(c2:Customer)
    WHERE s2.OrderDateKey=odk AND c2.CustomerKey<>customerKey
    WITH customerKey
    WHERE c2 IS NULL
    RETURN DISTINCT customerKey;
    

    【讨论】:

    • 如果 CustomerKey 唯一标识了一个客户(询问者必须澄清),那么我们根本不需要使用 CustomerKey,我们可以传递c1,并在WHERE 子句。
    • 即使我们可以这样做,也可能不会加快查询速度。
    • 可能不会。不过,我确实更喜欢在可能的情况下使用节点而不是属性值(它不会对性能产生影响),尤其是当我们从 SQL 转换为 Cypher 时。 SQL 都是关于连接和外键的,但在 Cypher 中我们应该使用关系和模式匹配。我认为放弃使用这些密钥以更好地鼓励最佳 Cypher 实践是一个好主意。
    • @InverseFalcon 是的,CustomerKey 唯一标识了一个客户,所以两个答案都有效!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多