添加唯一约束但忽略现有表数据

Posted

技术标签:

【中文标题】添加唯一约束但忽略现有表数据【英文标题】:Add a unique constraint but ignore existing table data 【发布时间】:2017-07-20 10:57:47 【问题描述】:

我希望使用以下查询向表中添加唯一约束 -

ALTER TABLE events ADD CONSTRAINT events_timestamp_request_session_key UNIQUE (event_timestamp, request_id, session_id);

查询有效,但是在一个数据库上现有数据不满足约束,因此查询失败-

错误:无法创建唯一索引“events_timestamp_request_session_key” DETAIL: Key (event_timestamp, request_id, session_id)=(2017-07-05 14:53:25.475246+00, a55df6-8533e322cd-aa9d57-87e2, 132443) 重复。

预计会有一些重复,但不幸的是我不能简单地删除或更改它们。

有没有什么方法可以根据需要添加约束,同时忽略表中已有的数据?

【问题讨论】:

【参考方案1】:

您可以为此使用部分索引,这不是一个特别好的解决方案,但在您可以更正旧数据之前它会起作用。

类似:

CREATE UNIQUE INDEX events_timestamp_request_session_key
ON events (event_timestamp, request_id, session_id)
WHERE event_timestamp >= '2017-07-01'::timestamp;

时间是清理数据的开始时间。

where 子句将索引限制为仅查看具有较新事件时间戳的记录。旧记录完全从索引中排除,因此不考虑进行唯一性检查。

文档:https://www.postgresql.org/docs/9.6/static/indexes-partial.html

【讨论】:

它起作用并强制这些列的组合是唯一的,所以谢谢你。不过,展望未来,您知道对查询的影响会是什么吗? IE。每周添加大约 300 万行,查询会比使用唯一约束时慢吗?谢谢。 @David Gard。插入会更慢,因为它们必须维护额外的索引。您需要进行基准测试以确定这是否会导致您出现问题。需要考虑的一件事是,因为这是一个部分索引,它对您想要运行的任何可能查看旧数据的查询没有帮助,因此您可能会发现自己需要 2 个索引,一个用于部分表的唯一索引,以及一个整个表的非唯一一个。【参考方案2】:

我认为没有内置的方法可以做到这一点。但是,您可以使用表达式创建唯一索引。让我假设您在每个表中都有一个序列唯一 ID:

create unique index unq_events_timestamp_request_session_key 
    on (event_timestamp, request_id, session_id,
        (case when event_id < 99999 then event_id else -1 end)
       ); 

该表达式本质上是说:“如果该键已经在表中,则将其忽略为唯一约束”。

您可以通过消除它们来对所有当前重复项强制执行唯一约束:

create unique index unq_events_timestamp_request_session_key 
    on (event_timestamp, request_id, session_id,
        (case when event_id in (1, 2, 3, 5, 8) then event_id
              else -1
         end)
       ); 

这需要研究当前的副本。实际上,您也可以使用过滤子句:

create unique index unq_events_timestamp_request_session_key 
    on (event_timestamp, request_id, session_id)
    where event_id > 999999 ;

create unique index unq_events_timestamp_request_session_key 
    on (event_timestamp, request_id, session_id)
    where event_id not in (1, 2, 3, 5, 8) ;

【讨论】:

以上是关于添加唯一约束但忽略现有表数据的主要内容,如果未能解决你的问题,请参考以下文章

我可以向 MySQL 中的列组合添加唯一约束吗? [复制]

SQLServer之UNIQUE约束

SQLServer之UNIQUE约束

添加索引迁移中的唯一性被忽略

如何绕过唯一约束违规?

mysql唯一约束