Postrgersql+Django:NULL值导致IntegrityError:重复键值违反唯一约束

Posted

技术标签:

【中文标题】Postrgersql+Django:NULL值导致IntegrityError:重复键值违反唯一约束【英文标题】:Postrgersql+Django: NULL value causes IntegrityError: duplicate key value violates unique constraint 【发布时间】:2014-02-23 14:24:02 【问题描述】:

我有下表:

   Column      |            Type             |                           Modifiers                           
----------------+-----------------------------+---------------------------------------------------------------
user_id         | bigint                      | not null default nextval('employee_user_id_seq'::regclass) 
name            | character varying(50)       | not null                                                      
phonenumber     | character varying(20)       | not null                                                      
phonenumber2    | character varying(20)       |                                                               
email           | character varying(75)       |      
Indexes:
"employee_pkey" PRIMARY KEY, btree (user_id)
"employee_email_key" UNIQUE CONSTRAINT, btree (email)
"employee_phonenumber2_key" UNIQUE CONSTRAINT, btree (phonenumber2)
"employee_phonenumber_email_key" UNIQUE CONSTRAINT, btree (phonenumber, email)
"employee_phonenumber_key" UNIQUE CONSTRAINT, btree (phonenumber)                                                         

在models.py中:

class Employee(models.Model):
    user_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=50)
    phonenumber = models.CharField(max_length=20, unique=True)
    phonenumber2 = models.CharField(max_length=20, unique=True)
    email = models.EmailField(blank=True, unique=True)

使用 Django,我在表中插入了一个没有 phonenumber2 的 Employee。第一次顺利,因为它是第一个 NULL,然后在第二次尝试时我得到了错误:

IntegrityError: duplicate key value violates unique constraint "employee_phonenumber2_key"
DETAIL:  Key (phonenumber2)=() already exists.

根据我的理解,NULL 不应被视为约束的值,我想要实现的是不能为不同的员工重复相同的电话号码或电话号码和电子邮件的组合。

我该如何解决这个问题?

【问题讨论】:

"models.py"。大胆猜测,您使用的是 Django 吗? (这是值得一提的事情,或者至少是标签)。 @CraigRinger 谢谢,我已经编辑了问题 【参考方案1】:

您根本没有真正插入NULL,而是插入了空字符串''。如果您插入的是NULL,则不可能得到您显示的错误。如果你想要一个唯一的约束来忽略NULL,你必须实际使用NULL

如果您检查 PostgreSQL 服务器错误日志,您将看到已运行的查询;不过,您可能需要打开 log_statement = all 以获取所有详细信息。它会显示你是 INSERTing '' 代表 phonenumber2,而不是 NULL

为了最终证明这一点:

ALTER TABLE employee ADD CONSTRAINT phonenumber2_nonempty 
CHECK (phonenumber2 IS NULL OR length(phonenumber2) > 0);

它将拒绝任何长度为零的字符串。包括你已经添加的那个你认为是空的,所以添加检查约束会失败。

您似乎正在使用 Django,因为您提到了“models.py”。 Django 有一个 IMO 糟糕的概念,即 Python 值 None 应该存储在字符字段中为 '',而不是 NULL;它将''None 都视为“空值”。 You can tell it to store None as NULL with Field.null。我不确定它是否还会强制将'' 存储为NULL;我希望不会,但尚未测试。

【讨论】:

@liva 如果您在研究了一段时间后无法弄清楚,请提出一个新问题。我不使用 Django。

以上是关于Postrgersql+Django:NULL值导致IntegrityError:重复键值违反唯一约束的主要内容,如果未能解决你的问题,请参考以下文章

Django 模型字段默认为 Null

Django 模型和 ModelForms 中的空白、Null 和必需

ForeignKey null=True 时 Django 慢查询

为啥django模型层的null和blank约束不起作用

我啥时候应该在 django 模型字段上使用 null=False

在 Django 模型中将 NULL 视为“0”