值类型的相等性、排序与比较

本页面解释了 Cypher® 如何比较和排列不同的值类型,包括相等和不等规则。

值的相等性与比较

相等 (=) 和不等 (<>) 运算符允许比较不同值的相等性。

相同类型的值只有在它们是完全相同的值时才相等(例如 3 = 3"x" <> "xy")。

映射 (Maps) 只有在映射完全相同的键到相等的值时才相等;列表 (Lists) 只有在包含完全相同序列的相等值时才相等(例如 [3, 4] = [1+2, 8/2])。

不同类型的值根据以下规则被视为相等:

  • PATH 值被视为节点和关系的交替列表,并且与所有包含节点和关系相同序列的列表相等。

  • 使用 =<> 运算符测试任何值与 null 的关系,结果总是 null。这包括 null = nullnull <> null。要可靠地测试一个值是否为 null,请使用 v IS NULLv IS NOT NULL(后者等同于 NOT(v IS NULL))。

其他值类型的组合彼此无法比较。例如,节点、关系和字面量映射之间无法比较。比较不可比较的值会抛出错误。

值的排序与比较

ORDER BY 要求所有值都是可排序的。以下几点解释了在使用 <=<>=> 运算符时如何进行比较。

  • 数值类型使用数值顺序进行排序比较(例如 3 < 4true)。

  • 所有与 java.lang.Double.NaN 的可比性测试结果均为 false。例如,当 b 为 NaN 时,1 > b1 < b 均为 false

  • 字符串值使用字典顺序进行排序比较(例如 "x" < "xy")。

  • 布尔值按照 false < true 的顺序进行排序。

  • 当比较排序值时,如果其中一个参数为 null,则结果总是 null

  • 空间值VECTOR 值不能使用 <=<>=> 运算符进行比较。若要在特定范围内比较空间值,请使用 point.withinBBox()point() 函数。

有关 VECTOR 类型的排序,请参阅 排序 VECTOR 类型

值层级

不同类型的值根据预定义的层级进行排序,从最小到最大,具体列表如下:

null 排在所有其他值之后。
混合 Cypher 类型的排序规则
WITH [42, "hello", null, true, {name: "Alice"}, [1, 2, 3], date("2024-02-10")] AS v
UNWIND v AS values
RETURN values
ORDER BY values
结果
值 (values)

{name: "Alice"}

[1, 2, 3]

2024-02-10

"hello"

true

42

null

行:7

排序列表和映射值

列表按字典顺序进行比较。

  • 元素从列表开头到结尾逐对比较。顺序由第一个元素不同的对定义。例如,[1, 'foo', 3] 小于 [1, 2, 'bar'],因为 'foo' 小于 2

  • 如果一个列表较短,则会用空元素填充,空元素被认为小于任何其他值(包括 null)。例如,[1, 'foo'] 小于 [1, 'foo', 3],且 [1] 小于 [1, null]

映射按大小、键和值排序。

  • 映射首先按大小比较:条目最少的映射最小。例如,{a: 1} 小于 {a: 0, b: 'foo'}

  • 相同大小的映射按键的字母顺序进行比较。例如,{b: 100, a: 'foo'} 小于 {a: '', c: null},因为 ['a', 'b'] 小于 ['a', 'c']

  • 对于具有相同键集的映射,比较基于值。按字母顺序对键排序后,逐对比较值。例如,{b: 100, a: 'foo'} 小于 {a: 'foo', b: null},因为 ['foo', 100] 小于 ['foo', null]

有关 LISTMAP 值的更多信息,请参阅 值与类型 → 构造类型

排序空间和时序值

以下内容适用于 空间类型 的排序:

  • POINT 值排在列表之后,时序类型之前。

  • 具有不同坐标参考系统 (CRS) 的 POINT 值按 CRS 代码(SRID 字段的值)排序。对于支持的 CRS 集合,适用以下升序:4326, 4979, 7302, 9157

  • 具有相同 CRS 的 POINT 值依次按每个坐标值排序;首先是 x,然后是 y,最后是 z

  • 请注意,此排序顺序与空间索引返回的顺序不同,后者遵循空间填充曲线。

以下内容适用于 时序类型 的排序:

  • 时序类型排在空间类型之后,但字符串之前。

  • 时序值遵循时间先后顺序。例如,2023-01-01 位于 2024-01-01 之前。

  • 时序值首先按类型排序,然后按值排序。例如,DATETIME 被认为比 DATE “大”,而 2023-02-10T12:00:00 位于 2023-02-10T15:00:00 之前,因为在时间上更早。

  • 由于无法完美比较持续时间 (Duration) 值(因为月和年的长度不同),Cypher 在 ORDER BY 中定义了特定的排序规则:

    • 1 年被视为 365.2425 天(考虑闰年)。

    • 1 月被视为 30.436875 天(即 1/12 年)。

    • 1 天始终为 24 小时。

以下内容适用于时序类型的比较:

  • 时序瞬间值 (Temporal instant values)(如 DATETIMEDATE)在类型相同时可以比较。较早的瞬间被视为小于较晚的瞬间。

  • 在同一时间点但处于不同时区的瞬间不被视为相等。为了确保一致的排序,Cypher 首先按其实际时间点排序。如果两个瞬间时间相同但时区不同,它们按 UTC 偏移量排序(从西到东,意味着负偏移量在前)。如果它们的时间和偏移量相同但命名的时区不同,则按时区名称按字母顺序排序。

  • 持续时间值不能直接比较。由于天、月或年的长度不固定,Cypher 未为持续时间定义严格的排序。因此,比较两个持续时间(例如 duration1 < duration2)总是返回 null

排序向量类型

VECTOR 超类型按以下升序排列:

  • VECTOR

  • VECTOR<TYPE>

  • VECTOR(DIMENSION)

同时定义了坐标类型和维度的 VECTOR 类型,根据向量坐标类型的顺序进行升序排列,如下所示:

  • INTEGER8

  • INTEGER16

  • INTEGER32

  • INTEGER64

  • FLOAT32

  • FLOAT64

在同一坐标类型内,VECTOR 类型按维度排序,值较小的在前。相同坐标类型和维度的 VECTOR 类型按值逐对排序。

VECTOR 值的排序规则
A B 排序方式 原因

VECTOR<FLOAT32>(12345)

VECTOR<FLOAT32>(123456)

A < B

坐标类型相同:按维度升序比较。

VECTOR<INTEGER32>(1234)

VECTOR<FLOAT32>(1234)

A < B

坐标类型顺序:INTEGER32 < FLOAT32

VECTOR<INTEGER8>

VECTOR(3)

A < B

定义了坐标类型但无维度 < 定义了维度但无坐标类型

VECTOR<INTEGER64>(123456)

VECTOR<FLOAT32>(3)

A < B

坐标类型顺序:INTEGER64 < FLOAT32,先比较坐标类型。

VECTOR<FLOAT64>(1234)

VECTOR<FLOAT32>(1234)

B < A

坐标类型顺序:FLOAT32 < FLOAT64

VECTOR<FLOAT32>([1, 2])

VECTOR<FLOAT32>([2, 1])

A < B

坐标类型和维度相同,按值逐对比较。

VECTOR<INTEGER16>(1234)

LIST<INTEGER>

A < B

VECTOR 值排在 LIST 值之前。