ORDER BY
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 属性的值进行升序排列。
| order | 总计 |
|---|---|
|
|
|
|
|
|
|
|
|
|
行: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 属性排序。
| order | 总计 | orderDate |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
行:5 |
||
ORDER BY 可用于按节点或关系的 ID 对其进行排序(通过 elementId() 或 id() 函数获取)。
MATCH (o:Order)
RETURN o.id AS order,
elementId(o) AS elementId
ORDER BY elementId
| order | elementId |
|---|---|
|
|
|
|
|
|
|
|
|
|
行: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
| order | discountedTotal |
|---|---|
|
|
|
|
|
|
|
|
|
|
行:5 |
|
接下来的这个查询 计算 了每个订单中包含的项数,然后按项数对结果进行排序。
MATCH (o:Order)
RETURN o.id AS order,
COUNT { (o)-[:CONTAINS]->(:Item) } AS itemCount
ORDER BY itemCount
| order | itemCount |
|---|---|
|
|
|
|
|
|
|
|
|
|
行:5 |
|
按结果中不包含的值排序
ORDER BY 可以按结果集中未包含的值进行排序。也就是说,排序键不必是先前 RETURN 或 WITH 子句的一部分。例如,下面的查询根据订单包含的项数对订单进行排序,即使该计数并未返回。
MATCH (o:Order)
RETURN o.id AS order
ORDER BY COUNT { (o)-[:CONTAINS]->(:Item) }
| order |
|---|
|
|
|
|
|
行:5 |
升序和降序
ORDER BY 默认按升序对结果进行排序。若要显式按升序排序,请附加 ASC[ENDING]。
MATCH (o:Order)
RETURN o.id AS order,
o.total AS total
ORDER BY total ASC
| order | 总计 |
|---|---|
|
|
|
|
|
|
|
|
|
|
行:5 |
|
若要按降序对结果进行排序,请附加 DESC[ENDING]。
MATCH (o:Order)
RETURN o.id AS order,
o.total AS total
ORDER BY total DESC
| order | 总计 |
|---|---|
|
|
|
|
|
|
|
|
|
|
行: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
| order | 总计 | orderDate |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
行: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
| order | 总计 | items |
|---|---|---|
|
|
|
行:1 |
||
Null 值
排序时,null 值在升序中排在最后,在降序中排在最前。
MATCH (o:Order)
RETURN o.id AS order,
o.status AS status
ORDER BY status DESC
| order | 状态 (status) |
|---|---|
|
|
|
|
|
|
|
|
|
|
行: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
| order | orderedListOfItems |
|---|---|
|
|
|
|
|
|
|
|
|
|
行:5 |
|
对聚合或 DISTINCT 结果进行排序
ORDER BY 可用的变量取决于前面的 RETURN 或 WITH 子句是否执行聚合来组合结果,或者是否使用 DISTINCT 来去除重复项。
-
如果
RETURN或WITH不聚合值或不使用DISTINCT,则ORDER BY可以引用前面RETURN或WITH子句中引用的任何变量。
DISTINCT 的 WITH 子句之后的 ORDER BYMATCH (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 BYMATCH (o:Order)-[:CONTAINS]->(i:Item)
WITH collect(o.id) AS orders,
i.name AS items
ORDER BY o.orderDate
RETURN orders, items
42N44: error: 语法错误或访问规则冲突 - 无法访问的变量。当使用 42001:错误:语法错误或访问规则冲突 - 无效语法 |
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
| 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
| secondMostExpensiveItem | 价格 |
|---|---|
|
|
行:1 |
|