【发布时间】:2020-06-26 12:45:23
【问题描述】:
我需要对文本字段中的表实施唯一约束,以确保用户不会输入包含相同地址的行。不过我不想验证它,需要保留旧记录
我用无效子句做了一些检查约束,但不知道如何使它唯一
如何使唯一检查约束无效
【问题讨论】:
-
请提供样本数据和期望的结果,以便清楚您想要做什么。
标签: sql postgresql
我需要对文本字段中的表实施唯一约束,以确保用户不会输入包含相同地址的行。不过我不想验证它,需要保留旧记录
我用无效子句做了一些检查约束,但不知道如何使它唯一
如何使唯一检查约束无效
【问题讨论】:
标签: sql postgresql
我会在表格中添加一个新列:
ALTER TABLE atable ADD is_new boolean DEFAULT FALSE NOT NULL;
ALTER TABLE atable ALTER is_new SET DEFAULT TRUE;
那么旧的行就会被标记出来,你可以
CREATE UNIQUE ON atable (col1) WHERE is_new;
这将充当“条件唯一约束”。
请注意,添加具有默认值的列将导致 11 版之前的表重写(可能很慢)。
【讨论】:
你不能:
https://www.postgresql.org/docs/current/sql-altertable.html
"添加 table_constraint [无效]
此表单使用与 CREATE TABLE 相同的约束语法以及当前仅允许外键和 CHECK 约束的选项 NOT VALID 向表添加新约束。”
此外,CHECK 约束只能在当前行上起作用,因此它们不能在所有行中强制唯一性。要执行您想要的操作,您正在查看 ON INSERT 触发器。
【讨论】:
如果我理解正确,您可以使用标志来执行此操作。但是您想设置标志,以便每个现有地址的一行都设置了标志。
ALTER TABLE t ADD address_for_duplicates boolean DEFAULT true NOT NULL;
然后,对于现有的行,我会假设你有一个主键,pk:
update t
set address_for_duplicates = (seqnum = 1)
from (select t.*, row_number() over (partition by address order by pk) as seqnum
from t
) tt
where tt.pk = t.pk;
现在添加一个过滤的唯一索引:
create unique index unq_t_address_some_duplicates
on t(address)
where address_for_duplicates;
这将防止现有地址被复制(再次)以及新地址。
【讨论】: