带有 Null 值的 PostgreSQL 约束

问题描述 投票:0回答:4

我有这张桌子。我需要使 [seller_id、product_id、sold_out_date] 的组合唯一,但问题是

CONSTRAINT u_product UNIQUE (seller_id, product_id, sold_out_date)

无法阻止由于 NULL 值而导致的重复行。将其设为主键也不起作用,因为它不能为 NULL。

我需要它是唯一的原因是当产品售完时,将输入

sold_out_date
,当产品有货时,我需要创建一个新行,所以这三者的组合必须是独一无二。

创建此约束后,我想执行如下查询:

INSERT INTO my_table
(seller_id, product_id, sold_out_date)

VALUES (1, 'A', NULL)

ON CONFLICT DO NOTHING;

enter image description here

postgresql unique-constraint
4个回答
2
投票

而是像这样添加一个唯一索引,你会没事的

create unique index ux_indx on my_table(seller_id, product_id, coalesce(sold_out_date,'1990-01-01'));

db<>小提琴这里

如果您需要更新冲突:

INSERT INTO my_table
VALUES (1, 'A', NULL)
ON CONFLICT (seller_id, product_id, coalesce(sold_out_date,'1990-01-01')) DO UPDATE set sold_out_date = '2020-01-10';

1
投票

尝试使用排除

ALTER TABLE my_table
    ADD CONSTRAINT excl1 EXCLUDE USING btree (
    seller_id ASC NULLS LAST WITH =,
    product_id ASC NULLS LAST WITH =,
    COALESCE(sold_out_date, '2020-01-01') ASC NULLS LAST WITH =);

ON CONFLICT DO NOTHING
会起作用


1
投票

数据库中的常见做法是使用基于哈希的 id,因此您可以在这三个字段的组合上创建哈希并将其用作 id,然后在此 id 字段上创建主键约束,例如

    INSERT INTO my_table
(seller_id, product_id, sold_out_date, id)
VALUES (1, 'A', null, encode(digest(concat('1','A',null) , 'sha1'),'base64'))
ON CONFLICT DO NOTHING;

数据库中必须存在 pgcrypto 扩展,如果不使用:

create extension pgcrypto; 

0
投票

对于 PG v15 及更高版本,另一个选项是

NULLS NOT DISTINCT
:

CREATE UNIQUE INDEX ux_indx
ON my_table(seller_id, product_id, sold_out_date)
NULLS NOT DISTINCT;

这扭转了将所有 NULL 值视为不相等的通常行为。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.