2012-11-06 63 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的帖子以瞭解重要的限制。 –