【问题标题】:PostgreSQL 9.4 - Comparing NULL valuesPostgreSQL 9.4 - 比较 NULL 值
【发布时间】:2016-04-01 04:03:34
【问题描述】:

在正常情况下,将NULL 值与任何其他值进行比较会产生另一个NULL 值。

SELECT NULL = NULL;

返回NULL


the documentation, 9.23.5. Row Constructor Comparison 中所述,比较任意行时,这(大部分)成立:

SELECT ROW(1, NULL, 'baz text') = ROW(1, NULL, 'baz text'); 

返回NULL


但是,在比较定义明确的复合类型时,NULL 值被视为相等。

CREATE TYPE test_type AS (
    foo INTEGER,
    bar BIGINT,
    baz TEXT
);

SELECT (1, NULL, 'baz text')::test_type = (1, NULL, 'baz text')::test_type;

返回TRUE

这种行为似乎没有记录(我已经查看并发现没有提及该行为)。

我想使用这种行为来实现一些业务规则,并希望确保这样做是安全的。

  1. 这是否符合任何 SQL 规范?
  2. 有可能这会在未来发生变化吗?

【问题讨论】:

  • 为了获得稳定的结果,您始终可以使用:SELECT ROW(1, NULL, 'baz text') IS NOT DISTINCT FROM ROW(1, NULL, 'baz text');
  • @lad2025 - 我熟悉IS NOT DISTINCT FROM 子句;但是,我对与复合类型一起使用时的 = 运算符感兴趣
  • 这很有趣,我猜它比较的是字符串表示Demo。所以{ "type": "test_type", "value": "(,,)" }={ "type": "test_type", "value": "(,,)" } => 是的
  • @lad2025 - 哇...你的第二个测试(NULL,NULL, NULL)::test_type IS NULL 返回TRUE - 我发现SELECT ARRAY[NULL] IS NULL 更有趣返回FALSE (与这个问题无关,只是有趣)。
  • 这在docIf the expression is row-valued, then IS NULL is true when the row expression itself is null or when all the row's fields are null, while IS NOT NULL is true when the row expression itself is non-null and all the row's fields are non-null.中有描述

标签: postgresql postgresql-9.4


【解决方案1】:

我在official documentation 中发现了这一点:[...] 在比较两个复合类型值的其他上下文中,两个 NULL 字段值被认为是相等的,并且 NULL 被认为大于非空值。为了使复合类型具有一致的排序和索引行为,这是必要的。。我认为这可以解决您的问题。

【讨论】:

    【解决方案2】:

    插图(抱歉,我不能在评论中这样做,需要格式):

    CREATE TYPE test_type AS (
        foo INTEGER
        , bar BIGINT
        , baz TEXT
        );
    
            -- plain table with three fields
    CREATE TABLE test_table0 (
        foo INTEGER
        , bar BIGINT
        , baz TEXT
        );
    
            -- the same, but with a composite type
    CREATE TABLE test_table1 (
            tt test_type
            );
    
    INSERT INTO test_table0 (foo,bar,baz)
            VALUES (1, NULL, 'baz text');
    
    INSERT INTO test_table1 (tt)
            VALUES( (1, NULL, 'baz text')::test_type) ;
    
            -- union needs a "whole row" -compare
    SELECT * FROM test_table0
    UNION
    SELECT * FROM test_table0
            ;
    
            -- union needs a "whole row" -compare
            -- and type needs a whole "composite" compare
    SELECT * FROM test_table1
    UNION
    SELECT * FROM test_table1
            ;
    

    结果:

    CREATE TYPE
    CREATE TABLE
    CREATE TABLE
    INSERT 0 1
    INSERT 0 1
     foo | bar |   baz    
    -----+-----+----------
       1 |     | baz text
    (1 row)
    
           tt        
    -----------------
     (1,,"baz text")
    (1 row)
    

    • 注意:比较的对象(类型实例和元组)不是 NULL,只是它们的一些元素。
    • 我确实认为这是预期的行为
    • 恕我直言,这接近于在复合键中允许 NULL 元素的问题,(请参阅 Chris Date 对此的咆哮)
    • 可能其他行为会导致更奇怪的人工制品

    【讨论】:

    • 我明白你在做什么,但我不确定我是否理解它的含义......你对这种行为在今天和未来是否应该被信任有任何意见吗?跨度>
    • 至少 UNION 构造依赖于整行的比较,即使其中有 NULL。是的:有些人依赖 UNION 来工作,如图所示。
    猜你喜欢
    • 1970-01-01
    • 2012-06-17
    • 1970-01-01
    • 2021-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多