排除了软删除行的唯一约束

时间:2012-11-06 22:28:22

标签: postgresql database-design constraints

我们有一个表格,上面有一个独特的约束,用于从一个用户留下的反馈,另一个与销售相关的反馈。

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,请考虑删除的反馈,但我们的数据库中仍然有审计跟踪(并且可能会将其显示给网站管理员)。

当我们使用像这样的软删除时,我们如何保持我们的唯一约束?是否可以在不使用更一般的CHECK()约束的情况下进行聚合检查(我从未尝试使用像这样的检查约束)。

就像我需要在约束中附加一个WHERE子句。

2 个答案:

答案 0 :(得分:15)

你的独特索引,后来被删除了。

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”时间戳中的的多行不同。所以可能最终得到的行看起来像下面的例子。这是否是一个问题取决于应用程序。
  3. 实施例

    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将此类索引记录为部分索引,如果您有时需要Google。其他平台使用不同的术语 - 过滤索引是一个。您可以使用一对部分索引在一定程度上限制问题。

    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”列而不是进行硬删除。

答案 1 :(得分:7)

尽管PostgreSQL文档建议不要使用唯一索引而不是约束(如果要点有约束),看起来你可以做到

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