Neo4J Cypher - Union & with Clause 用法



我正试图在查询中使用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中的所有子查询都必须具有相同的列名。有没有关于我哪里出了问题的信息?

我认为错误非常明显,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

您可以将多个用逗号分隔的短语传递给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

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

此外,在使用并集时,每个return子句返回的列名必须匹配。

我最终通过改变整体设计来解决这个问题,这将避免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);

为了提高该查询的性能,我们可以对时间戳即值属性进行索引。

最新更新