Man*_*duc 137 postgresql null constraint unique-constraint
我有一张如下表:
create table my_table (
id int8 not null,
id_A int8 not null,
id_B int8 not null,
id_C int8 null,
constraint pk_my_table primary key (id),
constraint u_constrainte unique (id_A, id_B, id_C)
);
Run Code Online (Sandbox Code Playgroud)
我想(id_A, id_B, id_C)在任何情况下都与众不同。所以下面的两个插入肯定会导致错误:
INSERT INTO my_table VALUES (1, 1, 2, NULL);
INSERT INTO my_table VALUES (2, 1, 2, NULL);
Run Code Online (Sandbox Code Playgroud)
但它没有按预期运行,因为根据文档,两个NULL值不会相互比较,因此两个插入都没有错误地通过。
我怎么能保证我的唯一约束,即使id_C可以NULL在这种情况下?实际上,真正的问题是:我可以在“纯 sql”中保证这种唯一性,还是必须在更高级别(在我的情况下为 java)来实现它?
Erw*_*ter 135
您可以在纯 SQL 中做到这一点。除了您拥有的索引之外 ,还创建一个部分唯一索引:
CREATE UNIQUE INDEX ab_c_null_idx ON my_table (id_A, id_B) WHERE id_C IS NULL;
Run Code Online (Sandbox Code Playgroud)
这样你就可以(id_A, id_B, id_C)在你的表中输入:
(1, 2, 1)
(1, 2, 2)
(1, 2, NULL)
Run Code Online (Sandbox Code Playgroud)
但这些都不是第二次。
或者使用两个部分UNIQUE索引而没有完整索引(或约束)。最佳解决方案取决于您的详细要求。相比:
虽然这对于UNIQUE索引中的单个可空列来说既优雅又高效,但对于不止一个列,它很快就会失控。讨论这个 - 以及如何将 UPSERT 与部分索引一起使用:
在 PostgreSQL 中不使用没有双引号的混合大小写标识符。
您可以将serial列作为主键或Postgres 10 或更高版本中的IDENTITY列。有关的:
所以:
CREATE TABLE my_table (
my_table_id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY -- for pg 10+
-- my_table_id bigserial PRIMARY KEY -- for pg 9.6 or older
, id_a int8 NOT NULL
, id_b int8 NOT NULL
, id_c int8
, CONSTRAINT u_constraint UNIQUE (id_a, id_b, id_c)
);
Run Code Online (Sandbox Code Playgroud)
如果您不希望在表的生命周期内有超过 20 亿行(> 2147483647)(包括浪费和删除的行),请考虑integer(4 字节)而不是bigint(8 字节)。
Luc*_*c M 17
我遇到了同样的问题,我找到了另一种方法来将唯一的 NULL 放入表中。
CREATE UNIQUE INDEX index_name ON table_name( COALESCE( foreign_key_field, -1) )
Run Code Online (Sandbox Code Playgroud)
就我而言,该字段foreign_key_field是一个正整数,永远不会是 -1。
因此,要回答 Manual Leduc,另一个解决方案可能是
CREATE UNIQUE INDEX u_constrainte (COALESCE(id_a, -1), COALESCE(id_b,-1),COALESCE(id_c, -1) )
Run Code Online (Sandbox Code Playgroud)
我假设 ids 不会是 -1。
创建部分索引有什么好处?
如果您没有 NOT NULL 子句,id_a,id_b和id_c只能同时为 NULL 一次。
对于部分索引,这 3 个字段可能不止一次为 NULL。
Null 可能意味着该行的值目前未知,但将来会在已知时添加(例如FinishDaterunning Project),或者不能为该行应用任何值(例如EscapeVelocityblack hole Star)。
在我看来,通过消除所有空值来规范化表格通常会更好。
在您的情况下,您希望NULLs在您的列中允许,但您只想允许一个NULL。为什么?这两张表是什么关系?
也许您可以简单地将列更改为NOT NULL并存储,而不是存储NULL一个-1已知永远不会出现的特殊值(如)。这将解决唯一性约束问题(但可能有其他可能不需要的副作用。例如,使用-1表示“未知/不适用”将歪曲列上的任何总和或平均值计算。或者所有此类计算都必须采用考虑特殊值并忽略它。)
| 归档时间: |
|
| 查看次数: |
126618 次 |
| 最近记录: |