2012-11-06 67 views
7

我们有一张表格,其中包含一个唯一的约束条件,用于反馈一个用户的反馈,另一个用于销售。排除软删除行的唯一约束条件

ALTER TABLE feedback 
ADD CONSTRAINT unique_user_subject_and_sale 
UNIQUE (user_id, subject_id, sale_id) 

这确保我们不会意外地得到重复的反馈行。

目前我们有时会硬删除反馈留下的错误,并且让用户再次离开。我们想改变软删除:

ALTER TABLE feedback 
ADD COLUMN deleted_at timestamptz 

如果deleted_at IS NOT NULL,考虑反馈删除,但我们仍然有审计跟踪我们的DB(并可能会显示它幻像出来的网站管理员)。

当我们使用像这样的软删除时,我们如何保持我们独特的约束?是否有可能没有使用一个更通用的约束呢做一个聚合检查(我从来没有尝试过使用检查约束)。

这就像我需要追加约束的WHERE子句。

回答

14

你的唯一索引,后来编辑了。

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale_null 
ON feedback(user_id, subject_id, sale_id) 
WHERE deleted_at IS NULL 

您的独特索引至少有两个副作用,可能会导致您一些麻烦。

  1. 在其他表中,您不能设置引用“反馈”的外键约束。外键引用要求将某些列的组合声明为primary keyunique
  2. 您的唯一索引允许在“deleted_at”时间戳中存在只有不同的行。所以它的可能结束与下面的例子看起来像行。这是否是一个问题取决于应用程序。

user_id subject_id sale_id deleted_at 
-- 
1  1   1  2012-01-01 08:00:01.33 
1  1   1  2012-01-01 08:00:01.34 
1  1   1  2012-01-01 08:00:01.35 

PostgreSQL的文档这种指标作为部分索引,你应该需要一段时间谷歌它。其他平台使用不同的术语 - 已过滤的索引就是其中之一。您可以用一对部分索引在一定程度上限制问题。

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale_null 
ON feedback(user_id, subject_id, sale_id) 
WHERE deleted_at IS NULL 

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale_not_null 
ON feedback(user_id, subject_id, sale_id) 
WHERE deleted_at IS NOT NULL 

我看不出有任何理由去这么多的麻烦,特别是考虑到与外键的潜在问题。如果你的餐桌看起来像这样

create table feedback (
    feedback_id integer primary key, 
    user_id ... 
    subject_id ... 
    sale_id ... 
    deleted_at ... 
    constraint unique_user_subj_sale 
    unique (user_id, subject_id, sale_id) 
); 

那么你需要的就是{user_id,subject_id,sale_id}上的唯一约束。您可能会进一步考虑使所有删除使用“deleted_at”列而不是进行硬删除。

+0

我没有发布完整模式,但反馈有一个整数(串行)主键。此外,user_id,sale_id和subject_id被声明为外键(并且具有索引)。我们只需要强制执行唯一性作为附加约束。 – d11wtq

+0

是的,对于唯一索引来说,它允许仅在deleted_at时间戳中有所不同的行是正确的......这是我试图实现的事情;) – d11wtq

+1

如果您有a)串行主键和b)部分如您所描述的那样,并且在我测试过的情况下,其他引用“反馈”的表格仍然存在潜在的问题。假设我在上面的示例中发布的三行具有串行主键1,2和3.哪个引用表选择其外键?如何知道所有引用表都会选择相同的*值? –

6

尽管PostgreSQL文档建议不要使用,而不是约束的唯一索引(如果该点是有一个约束)的事实,似乎可以做

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale 
ON feedback(user_id, subject_id, sale_id) 
WHERE deleted_at IS NULL 
+0

简称“部分指数”。请参阅@ Catcall的帖子以了解重要的限制。 –