【问题标题】:Neo4J Cypher - Union & With Clause usageNeo4J Cypher - Union 和 With 子句的用法
【发布时间】:2014-06-06 05:13:59
【问题描述】:

我正在尝试在查询中使用 UNION 创建发票产品子图,然后只想将使用 WITH 的发票节点传递给子查询。如下图所示

MATCH (year:Year)-[]->(month:Month)-[]->(day:Day)-[]->(inv:Invoice)-[]->(prd:Product)
WHERE year.value='2014' and day.value IN ['27','28','29','30','31'] and month.value='January'
RETURN (inv:Invoice)-[:PRODUCT]->(prd:Product)
UNION
MATCH (year:Year)-[]->(month:Month)-[]->(day:Day)-[]->(inv:Invoice)-[]->(prd:Product)
WHERE year.value='2014' and day.value IN ['01','02','03','04'] and month.value='February'
WITH inv
MATCH (inv)-[p:PROCESSED_AT]-(time:Time) WHERE p.time > 700 and p.time < 900
RETURN inv.invid

但我收到此错误 - UNION 中的所有子查询必须具有相同的列名。关于我在哪里出错的任何输入?

【问题讨论】:

    标签: neo4j union cypher with-statement


    【解决方案1】:

    我认为错误很明显,您的 UNION 的两个部分没有返回相同数量的列来建立联合。如果我理解正确,您正在尝试获取时间戳无效的特定产品的所有发票。我不认为如果是这种情况,您将需要一个 UNION 而您可能需要一个 WITH 子句。

    无论如何,要修复上述查询,您可能只想匹配 UNION 的两个部分,如下所示

    MATCH (year:Year)-[]->(month:Month)-[]->(day:Day)-[]->(inv:Invoice)-[]->(prd:Product)
    WHERE year.value='2014' and day.value IN ['27','28','29','30','31'] and month.value='January'
    MATCH (inv:Invoice)-[:PRODUCT]->(prd:Product)
    RETURN inv, prd
    UNION
    MATCH (year:Year)-[]->(month:Month)-[]->(day:Day)-[]->(inv:Invoice)-[]->(prd:Product)
    WHERE year.value='2014' and day.value IN ['01','02','03','04'] and month.value='February'
    WITH inv
    MATCH (prd:Product)<-[:PRODUCT]-(inv)-[p:PROCESSED_AT]-(time:Time) WHERE p.time > 700 and p.time < 900
    RETURN inv, prd
    

    .

    编辑

    我认为你有 UNIONRETURNWITH 有点偏离,老实说我不知道​​我们如何使用 UNION 连接 2 个结果,然后使用 WITH 缝合它到另一个查询。但是我认为您可以通过简单的重新排列连接来解决这个问题,如下所示

        MATCH (year:Year)-[]->(month:Month)-[]->(day:Day)-[]->(inv:Invoice)-[]->(prd:Product)
    WHERE year.value='2014' and ((day.value IN ['27','28','29','30','31'] and month.value='January') or (day.value IN ['01','02','03','04'] and month.value='February'))
    WITH inv
    MATCH (inv)-[p:PROCESSED_AT]-(time:Time) WHERE p.time > 700 and p.time < 900
    RETURN inv.invid
    

    【讨论】:

    • 可能还需要用AS columnName为RETURN中的列起别名
    • @DeepeshKuruppath:我编辑了查询,如果可行,您可以试一试
    • 感谢 Kiran - 该查询有效,但似乎我们要求此查询的返回始终为 inv,prd 这不是我的情况 - 我想通过多个传递此子图输出与子查询一起到达不同的输出,即使用这个inv prd 关系来导出时间、金钱关系并最终显示它。但是有了这个限制,我无法做到这一点......
    • “连接的简单重新排列”是矛盾的。
    【解决方案2】:

    您可以将多个用逗号分隔的短语传递给 MATCH,前提是它们构成一个连通图,这样可以简化您的问题。

    MATCH (year:Year)-[]->(month:Month)-[]->(day:Day)-[]->(inv:Invoice)-[]->(prd:Product)
    WHERE year.value='2014' and day.value IN ['01','02','03','04'] and month.value='February'
    WITH inv
    MATCH (prd:Product)<-[:PRODUCT]-(inv)-[p:PROCESSED_AT]-(time:Time) WHERE p.time > 700 and p.time < 900
    RETURN inv, prd
    

    可以变成:

    MATCH (year:Year)-[]->(month:Month)-[]->(day:Day)-[]->(inv:Invoice)-[]->(prd:Product), 
    (prd:Product)<-[:PRODUCT]-(inv)-[p:PROCESSED_AT]-(time:Time)
    WHERE p.time > 700 and p.time < 900
    RETURN inv, prd
    

    您可以类似地简化查询的前半部分。

    此外,当使用联合时,返回的列名必须与每个返回子句匹配。

    【讨论】:

    • 感谢这有帮助,我整体更改了设计以避免此类联合用例。
    【解决方案3】:

    我最终通过更改避免使用 UNION 的整体设计来解决这个问题。一种方法是将时间戳定义为单个实体,而不是将它们分别存储为年、月和日期。

    即添加如下时间节点

    //Add TimeStamp Nodes CREATE (datets1: DateTS {value:201401270730}) CREATE (datets2: DateTS {value:201401270800}) CREATE (datets3: DateTS {value:201401280745}) CREATE (datets4: DateTS {value:201402020815}) CREATE (datets5: DateTS {value:201402020830}) CREATE (datets6: DateTS {value:201402030702})

    注意 - 在我的情况下,我不需要秒和毫秒,所以它只是以小时和分钟分辨率结束。

    现在我将图表中的事件与这些节点相关联,然后查询变得非常简单,例如 MATCH (inv)-[:DATETIME]->(dts) WHERE dts.value <=201401280900 and dts.value >= 201401280700 RETURN distinct(inv.invid);

    为了提高这个查询的性能,我们可以索引时间戳,即值属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-30
      • 2015-03-10
      • 2014-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多