ORDER BY

ORDER BY 是一个子句,它决定 RETURNWITH 子句的结果如何排序。从 Neo4j 5.24 开始,它也可以作为一个独立子句使用,无论是单独使用还是与 SKIP/OFFSETLIMIT 结合使用。

ORDER BY 默认按升序对结果进行排序,但可以修改为按降序对结果进行排序。

ORDER BY 依靠比较来对输出进行排序(有关详细信息,请参阅值类型的相等性、排序和比较)。您可以根据不同的值进行排序,例如节点或关系的属性、ID 或表达式的结果。

除非使用 ORDER BY,否则 Neo4j 不保证查询结果的行顺序。

示例图

以下示例使用具有以下模式的图

graph order by clause

要重新创建它,请对空 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)

基本示例

示例 1. 按属性值排序

ORDER BY 可用于按属性值对结果进行排序。

按节点属性排序
MATCH (o:Order)
RETURN o.id AS order,
       o.total AS total
  ORDER BY total

返回节点,按 total 属性的值升序排序。

结果
订单 总计

"ORD-004"

200

"ORD-001"

550

"ORD-003"

550

"ORD-005"

800

"ORD-002"

1000

行数:5

示例 2. 按多个属性值排序

通过在 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 属性排序。

结果
订单 总计 订单日期

"ORD-004"

200

2024-05-04T12:45Z

"ORD-001"

550

2024-05-01T10:00Z

"ORD-003"

550

2024-05-03T09:15Z

"ORD-005"

800

2024-05-05T15:00Z

"ORD-002"

1000

2024-05-02T14:30Z

行数:5

示例 3. 按 ID 排序

ORDER BY 可用于按节点或关系的 ID 进行排序(通过 elementId()id() 函数检索)。

按元素 ID 排序
MATCH (o:Order)
RETURN o.id AS order,
       elementId(o) AS elementId
  ORDER BY elementId
结果
订单 元素 ID

"ORD-001"

"4:9350eddd-5a35-413d-8684-708b1da35d23:0"

"ORD-002"

"4:9350eddd-5a35-413d-8684-708b1da35d23:1"

"ORD-003"

"4:9350eddd-5a35-413d-8684-708b1da35d23:2"

"ORD-004"

"4:9350eddd-5a35-413d-8684-708b1da35d23:3"

"ORD-005"

"4:9350eddd-5a35-413d-8684-708b1da35d23:4"

行数:5

当节点和关系被删除时,Neo4j 会重用其内部 ID。因此,依赖内部 Neo4j ID 的应用程序是不稳定的,并且可能不准确。建议使用应用程序生成的 ID。
示例 4. 按表达式排序

ORDER BY 可用于根据表达式的结果进行排序。以下查询计算每个订单 total 属性值的 10% 折扣,然后按折扣后的总额对结果进行排序。

按表达式结果排序
MATCH (o:Order)
RETURN o.id AS order,
       o.total * 0.9 AS discountedTotal
  ORDER BY discountedTotal
结果
订单 折扣后总额

"ORD-004"

180.0

"ORD-001"

495.0

"ORD-003"

495.0

"ORD-005"

720.0

"ORD-002"

900.0

行数:5

下一个查询计算每个订单中包含的商品数量,然后按商品数量对结果进行排序。

按表达式结果排序
MATCH (o:Order)
RETURN o.id AS order,
      COUNT { (o)-[:CONTAINS]->(:Item) } AS itemCount
  ORDER BY itemCount
结果
订单 商品数量

"ORD-002"

1

"ORD-004"

1

"ORD-001"

2

"ORD-003"

2

"ORD-005"

3

行数:5

按不在结果中的值排序

ORDER BY 可以按不包含在结果集中的值进行排序。也就是说,排序键不需要是前面的 RETURNWITH 子句的一部分。例如,下面的查询根据订单中包含的商品数量对订单进行排序,即使该计数未返回。

按未返回结果中的值排序
MATCH (o:Order)
RETURN o.id AS order
  ORDER BY COUNT { (o)-[:CONTAINS]->(:Item) }
结果
订单

"ORD-002"

"ORD-004"

"ORD-001"

"ORD-003"

"ORD-005"

行数:5

升序和降序

ORDER BY 默认按升序对结果进行排序。要显式按升序对结果进行排序,请附加 ASC[ENDING]

显式按升序排序结果
MATCH (o:Order)
RETURN o.id AS order,
       o.total AS total
  ORDER BY total ASC
结果
订单 总计

"ORD-004"

200

"ORD-001"

550

"ORD-003"

550

"ORD-005"

800

"ORD-002"

1000

行数:5

要按降序对结果进行排序,请附加 DESC[ENDING]

按降序排序结果
MATCH (o:Order)
RETURN o.id AS order,
       o.total AS total
  ORDER BY total DESC
结果
订单 总计

"ORD-002"

1000

"ORD-005"

800

"ORD-001"

550

"ORD-003"

550

"ORD-004"

200

行数: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
结果
订单 总计 订单日期

"ORD-002"

1000

2024-05-02T14:30Z

"ORD-005"

800

2024-05-05T15:00Z

"ORD-001"

550

2024-05-01T10:00Z

"ORD-003"

550

2024-05-03T09:15Z

"ORD-004"

200

2024-05-04T12:45Z

行数:5

ORDER BY 和模式匹配

ORDER BY 可用于在继续进行其他模式匹配之前对结果进行排序。在下面的示例中,它与 LIMIT 结合使用,首先按 Order 节点的 orderDate 属性值进行排序,将结果限制为最近的 Order,然后匹配任何连接的 Item 节点。另请注意,在此示例中,ORDER BYLIMIT 用作独立子句,而不是子子句。

查找最近下的订单中包含的商品
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
结果
订单 总计 商品

"ORD-005"

800

["Phone", "Headphones", "Charger"]

行数:1

空值

排序时,null 值在升序中出现在最后,在降序中出现在最前面。

按空属性排序
MATCH (o:Order)
RETURN o.id AS order,
       o.status AS status
  ORDER BY status DESC
结果
订单 状态

"ORD-004"

null

"ORD-001"

"shipped"

"ORD-005"

"shipped"

"ORD-002"

"pending"

"ORD-003"

"pending"

行数:5

ORDER BY 和 WITH 子句

ORDER BY 出现在 WITH 子句上时,紧随其后的子句将按指定顺序接收记录。这种保证的顺序对于依赖于值处理顺序的操作非常有用。例如,将 ORDER BY 附加到 WITH 子句可以用于控制由 collect() 聚合函数生成的列表中项的顺序。MERGESET 子句也具有排序依赖性,可以通过这种方式进行控制。

以下示例使用 WITHORDER BYItem 节点的 price 属性对其进行排序,然后后续 RETURN 子句中的 collect() 根据该排序为每个订单构建一个有序列表。

WITHORDER BYcollect()
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
结果
订单 有序商品列表

"ORD-002"

["Laptop ($1000)"]

"ORD-001"

["Phone ($500)", "Charger ($50)"]

"ORD-003"

["Phone ($500)", "Charger ($50)"]

"ORD-005"

["Phone ($500)", "Headphones ($250)", "Charger ($50)"]

"ORD-004"

["Keyboard ($200)"]

行数:5

聚合或 DISTINCT 结果的排序

ORDER BY 可用的变量取决于前面的 RETURNWITH 子句是否执行聚合以组合结果或使用 DISTINCT 删除重复项。

  • 如果 RETURNWITH 未聚合值或未使用 DISTINCT,则 ORDER BY 可以引用前面 RETURNWITH 子句中引用的任何变量。

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
  • 如果 RETURNWITH 执行聚合或使用 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/OFFSETLIMIT 结合使用。

ORDER BY 的独立使用
MATCH (i:Item)
ORDER BY i.price
RETURN collect(i.name || " ($" || toString(i.price) || ")") AS orderedPriceList
结果
有序价格列表

["Charger ($50)", "Keyboard ($200)", "Headphones ($250)", "Phone ($500)", "Laptop ($1000)"]

行数:1

ORDER BYSKIPLIMIT 结合使用
MATCH (i:Item)
ORDER BY i.price DESC
SKIP 1
LIMIT 1
RETURN i.name AS secondMostExpensiveItem,
       i.price AS price
结果
第二昂贵的商品 价格

"Phone"

500

行数:1

© . All rights reserved.