暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PgSQL-NULL值处理-两个令人兴奋的功能

yanzongshuaiDBA 2023-11-23
491
PG的两个功能,可使NULL值的处理更加合理。

1、唯一列中的NULL值

一个众所周知,但令人讨厌的特性:NULL值的处理:NULL!=NULL,因此一个UNIQUE列仍可以有多个NULL值。
    CREATE TABLE test (
    id serial PRIMARY KEY,
    value TEXT UNIQUE
    );


    INSERT INTO test (value) VALUES ('a');


    -- This fails on the duplicate:
    -- ERROR: duplicate key value violates unique constraint "test_value_key"
    -- DETAIL: Key (value)=(a) already exists.
    INSERT INTO test (value) VALUES ('a');


    -- But this does not:
    INSERT INTO test (value) VALUES (null);
    INSERT INTO test (value) VALUES (null);


    SELECT * from test;
    id | value
    ----+-------
    1 | a
    3 |
    4 |
    (3 rows)
    PG15发布了一个新功能,可以改变这种行为:UNIQUE NULLS NOT DISTINCT
      CREATE TABLE test (
      id serial PRIMARY KEY,
      value TEXT UNIQUE NULLS NOT DISTINCT
      );


      -- Now this fails on the second insert:
      -- ERROR: duplicate key value violates unique constraint "test_value_key"
      -- DETAIL: Key (value)=(null) already exists.
      INSERT INTO test (value) VALUES (null);
      INSERT INTO test (value) VALUES (null);

      2、确保一个单列有一个值

      常见用例是一个具有多个外键的表,但预计只会填充一个外键。例如,一个notifications表来表示发送的通知(例如电子邮件、短信等)。这些通知可能会被触发并关联我们系统中特定实体,例如order、user、company等。我们希望添加外键来表示此通知的用途,但我们只想填充其中一个:
        CREATE TABLE notifications (
        id serial,
        company_id INT REFERENCES companies (id),
        order_id INT REFERENCES orders (id),
        user_id INT REFERENCES users (id)
        );


        INSERT INTO notifications (company_id) VALUES (100);
        INSERT INTO notifications (order_id) VALUES (200);


        SELECT * from notifications;


        id | company_id | order_id | user_id
        ----+------------+----------+---------
        1 | 100 | |
        2 | | 200 |
        (2 rows)
        通常,会对这样的表添加一个约束以确保至少填充一列
          ALTER TABLE notifications
          ADD CONSTRAINT notifications_reference
          CHECK (company_id IS NOT NULL OR order_id IS NOT NULL OR user_id IS NOT NULL);
          但,这并不能阻止意外填充多个列。
            INSERT INTO notifications (company_id, order_id, user_id)
            VALUES (NULL, 300, 400);


            SELECT * from notifications;


            id | company_id | order_id | user_id
            ----+------------+----------+---------
            1 | 100 | |
            2 | | 200 |
            3 | | 300 | 400
            (3 rows)
            有一对函数可以提供更好的约束检查:num_nulls/num_nonnulls。可以检查一组列中是否只有一个非NULL值,例如:
              ALTER TABLE notifications
              ADD CONSTRAINT notifications_reference
              CHECK (num_nonnulls(company_id, order_id, user_id) = 1);


              -- Now we get an error on insert if there is more than one value:
              -- ERROR: new row for relation "notifications" violates check constraint "notifications_reference"
              -- DETAIL: Failing row contains (3, null, 300, 400).
              INSERT INTO notifications (company_id, order_id, user_id)
              VALUES (NULL, 300, 400);


              -- Or if there are no values:
              -- ERROR: new row for relation "notifications" violates check constraint "notifications_reference"
              -- DETAIL: Failing row contains (4, null, null, null).
              INSERT INTO notifications (company_id, order_id, user_id)
              VALUES (NULL, NULL, NULL);

              3、原文

              https://www.pgrs.net/2023/11/14/two-exciting-postgresql-features-to-improve-null-handling/

              文章转载自yanzongshuaiDBA,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论