• PostgreSQL的空串、空值对唯一性约束的影响


    一、现象及原因

    今天在PostgreSQL又遇到一个现象,应用代码报错:“ERROR: duplicate key value violates unique constraint ...”。最后查明,这是由于PostgreSQL把空串('')、空值(NULL)当作不同的值,从而影响了那些没有申明为NOT NULL字段的unique约束。

    二、问题重现

    为重现问题,创建测试表如下:

    create table tt1
    (
      id int not null,
    name
    varchar(20), unique (name) );

    然后向该表插入测试记录:

    pgtest=# insert into tt1 values(1, 'OK');
    INSERT 0 1
    pgtest=# insert into tt1 values(2, null);
    INSERT 0 1
    pgtest=# insert into tt1 values(3, null);
    INSERT 0 1
    pgtest=# insert into tt1 values(4, '');
    INSERT 0 1
    pgtest=# insert into tt1 values(5, '');
    ERROR:  duplicate key value violates unique constraint "tt1_name_key"
    描述:  Key (name)=() already exists.

    可见,在PostgreSQL中空值(NULL)与空串(‘’)并非等同,且NULL不影响unique约束。再查找PostgreSQL资料,果然如此。

    在Oracle中,对于varchar类型,空值(NULL)与空串(‘’)总是被判定相同,所以多处代码对此不加区分,结果总是符合预期。但移植到PostgreSQL后就会产生问题,除了已提到的影响unique约束外,查询时如果条件是isnull 或=''也会出现查不全的现象。

    三、解决方法

    常见的解决方法有两种。其一是最彻底的方法即全面检查应用代码,将赋空串的地方全改为赋空值;但此方法对已有项目来说工作量巨大,难以实施下去,只能在新项目中推广。其二属于变通方法即对表创建触发器,在插入或修改之前将约束字段的空串自动修改为空值。示例脚本:

    CREATE OR REPLACE FUNCTION TF_BLANK2NULL() RETURNS TRIGGER
    AS $TFHS_BLANK2NULL$
    BEGIN
       IF (NEW.name='') THEN NEW.name:=NULL; END IF;
       RETURN NEW;
    END;
    $TFHS_BLANK2NULL$ LANGUAGE PLPGSQL;
    
    CREATE TRIGGER TG_BLANK2NULL BEFORE INSERT OR UPDATE ON tt1  FOR EACH ROW EXECUTE PROCEDURE TF_BLANK2NULL();

    四、注意事项

    • 如果约束字段已经申明为NOT NULL,则无需担心;
    • 触发器必须是BEFORE而不能是AFTER,另外不必考虑DELETE操作;
    • 查询条件中用“=''”在PostgreSQL是可行的,但在Oracle中无效;
    • 以上unique约束针对单一字段,但同样可推广到多个字段联合时的情况。
  • 相关阅读:
    普林斯顿宣布开源 25 核处理器
    瑞芯微RK3399宣布系统开源,进入百余种行业市场!
    Qt浅谈之二十App自动重启及关闭子窗口
    学在LINUX下编程(各种情况比较详细)
    ASP.NET开发规范:OWIN
    IDEA14中安装go语言插件
    sqlserver不能直接create table as select
    表复制语句select into from 与 insert into select 区别鉴赏
    实现Asp.net Mvc分布式Session Redis群集
    大小端模式
  • 原文地址:https://www.cnblogs.com/wggj/p/7818645.html
Copyright © 2020-2023  润新知