【问题标题】:What in the SQL or PostgreSQL specification explains comparison of arrays vs primitives?SQL 或 PostgreSQL 规范中的哪些内容解释了数组与原语的比较?
【发布时间】:2026-01-05 01:30:01
【问题描述】:

我希望了解为什么您可以在数组中将空值作为相等的值进行比较,但不能作为原语进行比较。

例如,以下查询演示:

SELECT NULL = NULL AS does_not_equal
     , NULL::bool = NULL::bool AS does_equal
     , NULL::int =  NULL::int AS does_equal
     , NULL::text = NULL::text AS does_equal
     , ARRAY[NULL] = ARRAY[NULL] AS does_equal
     , ARRAY[NULL]::bool[] = ARRAY[NULL]::bool[] AS does_equal
     , ARRAY[NULL]::int[] = ARRAY[NULL]::int[] AS does_equal
     , ARRAY[NULL]::text[] = ARRAY[NULL]::text[] AS does_equal
;

我理解为什么 NULL = NULL 对于基元来说是 NULL,而且我也想我理解为什么比较复合类型会为它们中的一个两边都为 null 的字段提供一个真正的比较,主要是因为 *= 运算符看起来在类型的二进制值。但是数组似乎没有使用 *= 运算符,到目前为止,我在搜索中找不到任何解释它的东西。

【问题讨论】:

    标签: sql postgresql null


    【解决方案1】:

    这是一个复杂的故事。

    这是 SQL 标准 (ISO/IEC 9075-2) 在“8.2 ”:

    XVYV分别为XY表示的两个值.结果:

    <em>X</em> &lt;comp op&gt; <em>Y</em>

    确定如下:
    案例:

    1. 如果 XVYV 为空值,则

      <em>X</em> &lt;comp op&gt; <em>Y</em>

      未知。

    2. 否则,

      案例:

      1. 如果XVYV声明的类型是度为N的行类型,则令Xi,1(一)≤iN, 表示一个 ,其值和声明的类型是 XV 的第 i 字段的值和声明的类型,并且 令 Yi 表示一个 ,其值和声明类型是 YV 的第 i 字段的值和声明类型em>.
        结果

        <em>X</em> &lt;comp op&gt; <em>Y</em>

        确定如下:

        1. X = YTrue 当且仅当 Xi = 对于所有 i,YiTrue
        2. X Y 是 True 当且仅当 Xi = 对于所有 i nXn,YiTrue = Yn 对于一些 n
        3. X = YFalse 当且仅当 NOT (Xi = Yi) 对于某些 i 来说是 True
        4. X Y 为 False 当且仅当 X = YY X是
        5. X Y 如果 X Y未知既不是 True 也不是 False
      2. 如果声明的XVYV类型是基数分别为N1N2的数组类型, 那么令Xi,1(一)≤iN1,表示一个,其值声明的类型是 XV 的第 i 个元素,并让 Yi 表示一个 ,其值和声明类型 是 YV 的第 i 个元素。结果

        <em>X</em> &lt;comp op&gt; <em>Y</em>

        确定如下:

        1. X = YTrue 如果 N1 = 0(零)并且 N2 = 0(零)。
        2. X = YTrue 如果 N1 = N2 并且对于所有 i, Xi = Yi
        3. X = YFalse 当且仅当 N1N2 或 NOT ( Xi = Yi) 是 True,对于某些 i
        4. X Y 如果 X Y未知既不是 True 也不是 False

    这很令人困惑,例如,我没有看到将数组与等式运算符进行比较的规范。

    该标准有时也会自相矛盾。

    *= 运算符仅适用于 record,不适用于数组。它与= 几乎相同,但效率更高,因为如果它们的长度不同,它不会“解除”值。

    最好是接受语义原样。

    PostgreSQL 似乎没有遵循这个标准。

    NULL 本身令人困惑,组合或数组中的 NULL 更是如此。

    【讨论】:

    • 非常感谢。我询问的目的是确定我是否可以依赖这样一个事实,即我可以从一组数组值中获得所需的布尔比较结果,即使如果这些值不在数组中(例如评估时)我会得到未知结果在 unnest() 之后的行上下文中。
    • 如你所见,结果会有所不同。
    【解决方案2】:

    我找不到您描述的行为的文档。但是,NULLs 被认为对于记录和行构造函数是相等的,这已明确解释:

    SQL 规范要求逐行比较返回 NULL,如果 结果取决于比较两个 NULL 值或一个 NULL 和一个 非空。 . . .在其他两个复合类型值是 比较,两个 NULL 字段值被认为是相等的,一个 NULL 是 认为大于非 NULL。

    数组不是复合类型。似乎正在使用类似的逻辑。

    【讨论】: