2010-08-16 188 views
9

假設我有兩個表,usercomment。他們有看起來像這樣的表定義:MySQL軟刪除,唯一鍵和外鍵約束

CREATE TABLE `user` (
    `id`  INTEGER NOT NULL AUTO_INCREMENT, 
    `username` VARCHAR(255) NOT NULL, 
    `deleted` TINYINT(1) NOT NULL DEFAULT 0, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY (`username`) 
) ENGINE=InnoDB;
CREATE TABLE `comment` (
    `id`  INTEGER NOT NULL AUTO_INCREMENT, 
    `user_id` INTEGER NOT NULL, 
    `comment` TEXT, 
    `deleted` TINYINT(1) NOT NULL DEFAULT 0, 
    PRIMARY KEY (`id`), 
    CONSTRAINT `fk_comment_user_id` FOREIGN KEY (`user_id`) 
    REFERENCES `user` (`id`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE 
) ENGINE=InnoDB;

這是偉大的強制執行數據的完整性和所有這一切,但我希望能夠以「刪除」用戶,並保持其所有評論(供參考的清酒)。

爲此,我添加了deleted以便我可以在記錄上SET deleted = 1。通過默認列出一切與deleted = 0,我可以隱藏所有刪除的記錄,直到我需要他們。

到目前爲止這麼好。

問題是當:

  • 用戶登錄了一個用戶名(比如,「薩姆」),
  • 我軟刪除用戶(不相關的原因),並
  • 有人否則會以Sam身份註冊,突然我們違反了user上的UNIQUE約束。

我希望用戶能夠編輯自己的用戶名,所以我不應該讓username主鍵和刪除用戶的時候我們仍然有同樣的問題。

有什麼想法?

編輯澄清:添加以下RedFilter的答案,下面的評論。

我關心的情況是,「刪除」的用戶和評論對公衆不可見,但只有管理員可見,或者爲了計算統計而保留。

這個問題是一個思想實驗,用戶和評論表僅僅是示例。儘管如此,username並不是最好的選擇; RedFilter提供有關用戶身份的有效信息,特別是當記錄顯示​​在公共場合時。

關於「爲什麼不是用戶名的主鍵?」:這只是一個例子,但如果我申請這一個真正的問題,我會需要到它假定現有系統的約束下工作代理主鍵的存在。

回答

22

爲字段(用戶名,刪除)添加唯一約束 將'deleted'的字段類型更改爲INTEGER。

在刪除操作期間(可以在觸發器中完成,或者在需要實際刪除用戶的代碼的一部分中)複製id字段的值到刪除字段。

這種方法允許你:

  • 保持唯一的名稱爲活躍用戶(刪除= 0)
  • 允許使用相同的用戶名刪除用戶多次

字段 '刪除' 不能只有2個值,因爲以下場景不起作用:

  1. 您創建用戶'Sam'
  2. 用戶Sam被刪除
  3. 你創建新的用戶WITN用戶名「薩姆」
  4. 您嘗試刪除用戶帳號「薩姆」 - 失敗。你已經有記錄userName ='Sam'並刪除='1'
+5

將'deleted'的字段類型更改爲'timestamp'可讓您在此處添加更多已刪除的行。如果你想要現有的(未刪除的)記錄,請在這個字段中檢查'null'。 – 2013-01-02 06:57:08

+1

@TahaPaksu如果您允許刪除空值,您將失去唯一密鑰的值。 – 2016-03-15 20:18:46

+0

@eric_s這種方法需要像「除1之外的所有東西都被視爲'未被刪除'」。 – 2016-03-16 06:21:22

3

只需保留username上的唯一索引或約束。您不希望新用戶能夠使用已刪除的姓名,因爲不僅可能會對身份造成普遍的混淆,但是如果您仍然顯示已刪除用戶的舊帖子,則他們將被錯誤地理解爲由具有相同名稱的新用戶。

當新用戶註冊時,您通常會在允許註冊完成之前檢查名稱是否正在使用,因此這裏不應該有衝突。

+1

@RedFilter,它不是一個完整的解決方案 - 你不能將兩個'Sam'標記爲已刪除。在刪除操作過程中,更好地將Id複製到刪除的字段這使得只有一個人保持活動狀態,並且有幾個被刪除的用戶具有相同的名稱(通過使用const unique unique(name,deleted))。 – 2010-08-16 11:04:15

+1

@Michael:我不同意兩個單獨的用戶應該能夠使用相同的用戶名。 – RedFilter 2010-08-16 11:05:43

+1

@邁克爾:第一反應,「這是一個黑客」。第二個反應,「哇,這實際上很聰明」。 假設你的意思是將約束設置爲'UNIQUE KEY(username,deleted)'。 – 2010-08-16 11:08:37