ORDER BY
ORDER BY
是一个子句,它决定 RETURN
或 WITH
子句的结果如何排序。从 Neo4j 5.24 开始,它也可以作为一个独立子句使用,无论是单独使用还是与 SKIP
/OFFSET
或 LIMIT
结合使用。
ORDER BY
默认按升序对结果进行排序,但可以修改为按降序对结果进行排序。
ORDER BY
依靠比较来对输出进行排序(有关详细信息,请参阅值类型的相等性、排序和比较)。您可以根据不同的值进行排序,例如节点或关系的属性、ID 或表达式的结果。
除非使用 ORDER BY ,否则 Neo4j 不保证查询结果的行顺序。 |
示例图
以下示例使用具有以下模式的图
要重新创建它,请对空 Neo4j 数据库运行以下查询
CREATE (o1:Order {id: 'ORD-001', orderDate: datetime('2024-05-01T10:00:00'), total: 550, status: 'shipped'}),
(o2:Order {id: 'ORD-002', orderDate: datetime('2024-05-02T14:30:00'), total: 1000, status: 'pending'}),
(o3:Order {id: 'ORD-003', orderDate: datetime('2024-05-03T09:15:00'), total: 550, status: 'pending'}),
(o4:Order {id: 'ORD-004', orderDate: datetime('2024-05-04T12:45:00'), total: 200}),
(o5:Order {id: 'ORD-005', orderDate: datetime('2024-05-05T15:00:00'), total: 800, status: 'shipped'}),
(i1:Item {name: 'Phone', price: 500}),
(i2:Item {name: 'Laptop', price: 1000}),
(i3:Item {name: 'Headphones', price: 250}),
(i4:Item {name: 'Charger', price: 50}),
(i5:Item {name: 'Keyboard', price: 200}),
(o1)-[:CONTAINS]->(i1),
(o1)-[:CONTAINS]->(i4),
(o2)-[:CONTAINS]->(i2),
(o3)-[:CONTAINS]->(i1),
(o3)-[:CONTAINS]->(i4),
(o4)-[:CONTAINS]->(i5),
(o5)-[:CONTAINS]->(i1),
(o5)-[:CONTAINS]->(i3),
(o5)-[:CONTAINS]->(i4)
基本示例
ORDER BY
可用于按属性值对结果进行排序。
MATCH (o:Order)
RETURN o.id AS order,
o.total AS total
ORDER BY total
返回节点,按 total
属性的值升序排序。
订单 | 总计 |
---|---|
|
|
|
|
|
|
|
|
|
|
行数:5 |
通过在 ORDER BY
子句中列出两个或多个属性来按多个属性值排序。Cypher® 首先按第一个属性排序,如果值相等,则移动到下一个属性,依此类推。
MATCH (o:Order)
RETURN o.id AS order,
o.total AS total,
o.orderDate AS orderDate
ORDER BY total,
orderDate
这将返回节点,首先按其 total
属性排序,然后对于相等的值,按其 orderDate
属性排序。
订单 | 总计 | 订单日期 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
行数:5 |
ORDER BY
可用于按节点或关系的 ID 进行排序(通过 elementId()
或 id()
函数检索)。
MATCH (o:Order)
RETURN o.id AS order,
elementId(o) AS elementId
ORDER BY elementId
订单 | 元素 ID |
---|---|
|
|
|
|
|
|
|
|
|
|
行数:5 |
当节点和关系被删除时,Neo4j 会重用其内部 ID。因此,依赖内部 Neo4j ID 的应用程序是不稳定的,并且可能不准确。建议使用应用程序生成的 ID。 |
ORDER BY
可用于根据表达式的结果进行排序。以下查询计算每个订单 total
属性值的 10% 折扣,然后按折扣后的总额对结果进行排序。
MATCH (o:Order)
RETURN o.id AS order,
o.total * 0.9 AS discountedTotal
ORDER BY discountedTotal
订单 | 折扣后总额 |
---|---|
|
|
|
|
|
|
|
|
|
|
行数:5 |
下一个查询计算每个订单中包含的商品数量,然后按商品数量对结果进行排序。
MATCH (o:Order)
RETURN o.id AS order,
COUNT { (o)-[:CONTAINS]->(:Item) } AS itemCount
ORDER BY itemCount
订单 | 商品数量 |
---|---|
|
|
|
|
|
|
|
|
|
|
行数:5 |
按不在结果中的值排序
ORDER BY
可以按不包含在结果集中的值进行排序。也就是说,排序键不需要是前面的 RETURN
或 WITH
子句的一部分。例如,下面的查询根据订单中包含的商品数量对订单进行排序,即使该计数未返回。
MATCH (o:Order)
RETURN o.id AS order
ORDER BY COUNT { (o)-[:CONTAINS]->(:Item) }
订单 |
---|
|
|
|
|
|
行数:5 |
升序和降序
ORDER BY
默认按升序对结果进行排序。要显式按升序对结果进行排序,请附加 ASC[ENDING]
。
MATCH (o:Order)
RETURN o.id AS order,
o.total AS total
ORDER BY total ASC
订单 | 总计 |
---|---|
|
|
|
|
|
|
|
|
|
|
行数:5 |
要按降序对结果进行排序,请附加 DESC[ENDING]
。
MATCH (o:Order)
RETURN o.id AS order,
o.total AS total
ORDER BY total DESC
订单 | 总计 |
---|---|
|
|
|
|
|
|
|
|
|
|
行数:5 |
ORDER BY
可以结合升序和降序排序。在下面的示例中,结果首先按 total
值降序排序,然后按 orderDate
值升序排序。
MATCH (o:Order)
RETURN o.id AS order,
o.total AS total,
o.orderDate AS orderDate
ORDER BY total DESC,
orderDate ASC
订单 | 总计 | 订单日期 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
行数:5 |
ORDER BY 和模式匹配
ORDER BY
可用于在继续进行其他模式匹配之前对结果进行排序。在下面的示例中,它与 LIMIT
结合使用,首先按 Order
节点的 orderDate
属性值进行排序,将结果限制为最近的 Order
,然后匹配任何连接的 Item
节点。另请注意,在此示例中,ORDER BY
和 LIMIT
用作独立子句,而不是子子句。
MATCH (o:Order)
ORDER BY o.orderDate DESC
LIMIT 1
MATCH (o)-[:CONTAINS]->(i:Item)
RETURN o.id AS order,
o.total,
collect(i.name) AS items
订单 | 总计 | 商品 |
---|---|---|
|
|
|
行数:1 |
空值
排序时,null
值在升序中出现在最后,在降序中出现在最前面。
MATCH (o:Order)
RETURN o.id AS order,
o.status AS status
ORDER BY status DESC
订单 | 状态 |
---|---|
|
|
|
|
|
|
|
|
|
|
行数:5 |
ORDER BY 和 WITH 子句
当 ORDER BY
出现在 WITH
子句上时,紧随其后的子句将按指定顺序接收记录。这种保证的顺序对于依赖于值处理顺序的操作非常有用。例如,将 ORDER BY
附加到 WITH
子句可以用于控制由 collect()
聚合函数生成的列表中项的顺序。MERGE
和 SET
子句也具有排序依赖性,可以通过这种方式进行控制。
以下示例使用 WITH
和 ORDER BY
按 Item
节点的 price
属性对其进行排序,然后后续 RETURN
子句中的 collect()
根据该排序为每个订单构建一个有序列表。
WITH
、ORDER BY
和 collect()
MATCH (o:Order)-[:CONTAINS]->(i:Item)
WITH o, i
ORDER BY i.price DESC
RETURN o.id AS order,
collect(i.name || " ($" || toString(i.price) || ")") AS orderedListOfItems
订单 | 有序商品列表 |
---|---|
|
|
|
|
|
|
|
|
|
|
行数:5 |
聚合或 DISTINCT 结果的排序
ORDER BY
可用的变量取决于前面的 RETURN
或 WITH
子句是否执行聚合以组合结果或使用 DISTINCT
删除重复项。
-
如果
RETURN
或WITH
未聚合值或未使用DISTINCT
,则ORDER BY
可以引用前面RETURN
或WITH
子句中引用的任何变量。
WITH
子句(不包括聚合或 DISTINCT
)后的 ORDER BY
MATCH (o:Order)-[:CONTAINS]->(i:Item)
WITH o.id AS order,
i.name AS item
ORDER BY o.orderDate
RETURN order, item
-
如果
RETURN
或WITH
执行聚合或使用DISTINCT
,则只有来自任一操作的投影变量才可用于ORDER BY
。这是因为这些操作会改变子句生成的行数,并且任何未明确投影的变量都将被丢弃。
WITH
子句投影聚合值后的 ORDER BY
MATCH (o:Order)-[:CONTAINS]->(i:Item)
WITH collect(o.id) AS orders,
i.name AS items
ORDER BY o.orderDate
RETURN orders, items
In a WITH/RETURN with DISTINCT or an aggregation, it is not possible to access variables declared before the WITH/RETURN: o
ORDER BY 和索引
使用 ORDER BY
对节点属性进行排序的 Cypher 查询的性能可能会受到查找节点的索引的存在和使用的影响。如果索引可以按查询中请求的顺序提供节点,Cypher 可以避免使用昂贵的 Sort
操作。有关此功能的更多信息,请参阅范围索引支持的 ORDER BY。
将 ORDER BY
用作独立子句
ORDER BY
可以作为独立子句使用,也可以与 SKIP
/OFFSET
或 LIMIT
结合使用。
ORDER BY
的独立使用MATCH (i:Item)
ORDER BY i.price
RETURN collect(i.name || " ($" || toString(i.price) || ")") AS orderedPriceList
有序价格列表 |
---|
|
行数:1 |
ORDER BY
与 SKIP
和 LIMIT
结合使用MATCH (i:Item)
ORDER BY i.price DESC
SKIP 1
LIMIT 1
RETURN i.name AS secondMostExpensiveItem,
i.price AS price
第二昂贵的商品 | 价格 |
---|---|
|
|
行数:1 |