liv*_*v a 35 sql postgresql null database-design unique-constraint
我创建了下表:
CREATE TABLE MMCompany (
CompanyUniqueID BIGSERIAL PRIMARY KEY NOT NULL,
Name VARCHAR (150) NOT NULL,
PhoneNumber VARCHAR(20) NOT NULL UNIQUE,
Email VARCHAR(75) UNIQUE,
CompanyLogo BYTEA
);
Run Code Online (Sandbox Code Playgroud)
电子邮件列是唯一的,它在我的方案中导致"错误",因为只有一个记录为null.我试图获得没有相同电子邮件的公司记录,但同时允许公司没有电子邮件.
我怎样才能做到这一点?
Erw*_*ter 72
这是一种误解.
该UNIQUE约束不正是你想要的.多个NULL值可以在定义的列中共存UNIQUE.
通常,当表中有多行时,约束中包含的所有列的值相等,则违反了唯一约束.但是,在此比较中,两个空值不相等.这意味着即使存在唯一约束,也可以在至少一个约束列中存储包含空值的重复行.此行为符合SQL标准,但我们听说其他SQL数据库可能不遵循此规则.因此在开发可移植的应用程序时要小心.
大胆强调我的.
请注意,字符类型允许空字符串(''),这是不是一个NULL值,在多行输入的时候会触发一个独特违反就像任何其他非空值.
Bas*_*que 18
在Erwin Brandstetter的正确答案中,他解释说你确实应该看到你想要的行为(在Unique约束中允许多个NULL).您应该特别在Postgres中看到此行为以及任何符合SQL标准的数据库.
但是,Postgres doc警告可移植性,因为已知某些数据库违反了此功能.对于这种不兼容的系统,我建议用伪造的值替换这些字段中NULL值的使用.虚假值将是一个字符串,例如"unknown_"加上一些几乎肯定是唯一的任意值.任意值可能类似于当前日期时间加上随机数.
但是,不是滚动自己的任意值,而是生成UUID.原始版本1 UUID确实是当前日期时间,随机数和计算机的几乎唯一MAC地址的组合.
UUID呈现为带有使用连字符的规范格式的十六进制字符串,如下所示:
93e6f268-5c2d-4c63-9d9c-40e6ac034f88
所以我的建议是组合一个任意字符串,如"unknown_"加上一个UUID,看起来像这样:
unknown_93e6f268-5c2d-4c63-9d9c-40e6ac034f88
因此,我对不兼容数据库的建议是生成这样的值并使用它代替NULL,在特定行的该列中尚未具有已知值的情况下使用它.而不是编写查找在该列中具有(或没有)NULL值的行的查询,而是编写查询以查找具有(或没有)以任意字符串开头的值的行,在此处使用"unknown_"例.然后每行将满足具有唯一值的约束.
实际上,我会将此"unknown_"+ UUID值指定为该列的默认值.
您还可以向此列添加NOT NULL约束.
Postgres内置了对UUID数据类型的支持,但这里的答案与此无关.您需要的是生成UUID 值.
要生成UUID,您需要一个扩展(插件),将此功能添加到Postgres.大多数Postgres安装程序都包含此类扩展.这个扩展名为uuid-ossp.通常,默认情况下不会激活扩展名.要在最新版本的Postgres中执行此操作,请使用CREATE EXTENSION命令.有关说明,请参阅我在Postgres 9.1及更高版本中安装的博客文章或Postgres 9.0及更早版本中的其他帖子.如果扩展/插件已编译并与Postgres安装捆绑在一起,则新旧安装方式都很简单.
让我明确一点,仅对于Postgres,就没有必要采用这种解决方法,因为Postgres符合SQL标准.但如果:
...然后这样的解决方法是必要的.
一些数据库不允许多个空值,例如SQL Server文档指出“多个空值被视为重复”。在不允许可空UNIQUE约束的数据库上,您可以尝试以下操作(来自GuidoG对另一个问题的回答):
CREATE UNIQUE NONCLUSTERED INDEX IDX_Email
ON MMCompany (Email)
WHERE Email IS NOT NULL;
Run Code Online (Sandbox Code Playgroud)
从表中删除电子邮件列。将它放在一个新表中,它可以是 NOT NULL 和 UNIQUE:
CREATE TABLE CompanyEmail
(
CompanyUniqueID INT NOT NULL PRIMARY KEY
REFERENCES MMCompany (CompanyUniqueID),
Email VARCHAR(75) NOT NULL UNIQUE
);
Run Code Online (Sandbox Code Playgroud)
避免可为空的 UNIQUE 约束。