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

时间:2017-07-20 10:57:48

标签: sql postgresql unique-constraint

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

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

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

  

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

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

有没有办法根据需要添加约束,而忽略表中的现有数据?

2 个答案:

答案 0 :(得分:6)

您可以使用部分索引,这不是一个特别好的解决方案,但它会一直有效,直到您可以更正旧数据。

类似的东西:

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

其中时间是干净数据的开始。

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

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

答案 1 :(得分:1)

我认为没有内置方法可以做到这一点。但是,您可以使用表达式创建唯一索引。我假设您在每个表中都有一个序列唯一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) ;