2011-05-12 85 views
4

使用下面的表佈局:數據完整性和限制

TABLE Something 
(
    SomethingId    
    Name  
    DateCreated 
    IsObsolete ('Y','N')  
    PRIMARY KEY (SomethingId) 
    Foreign Key (SomethingTypeCode) 
; 


TABLE SomethingType 
(
    SomethingTypeCode ('1','2','3')    
    Description    
    PRIMARY KEY (SomethingTypeCode) 
); 

隨着PHP/MySQL的設置是有一些方法,我可以通過一個約束或索引,對於每個SomethingTypeCode限制(1,2,3)在Something表中標識,只能有一個IsObsolete = N與它關聯?

我希望能解釋我正在努力完成的事情。我只是不知道該如何解決這個問題。我希望數據完整性能夠在數據庫本身中儘可能地保持,然後將其擴展到PHP。


編輯:

在回答我與VoteyDisciple答案越來越混亂。

EmailTypeCode:P =個人,B =商務,S =學校

這裏是我的設計:

enter image description here

這將允許一個人有多於一個類型的電子郵件在一個給定的typecode(即2個業務電子郵件),並避免數據庫中的重複,不需要任何空值。由於我只關心在每個類別(系統將使用的那個)中有一個活動電子郵件,這是IsObsolete發揮作用的地方。我可以保留歷史記錄,避免重複,避免空值,並確保在此輸入系統的唯一電子郵件地址。

當然這也帶來了我原來的問題所述的問題。

VoteyDisciple的做法

VoteyDisciple請讓我知道,如果我把它描述錯誤(或正確的)。

enter image description here

「如果只能有一個給定類型」 - 只有一個活躍的不是時候,不僅是在系統中。
「現在ActiveId可以是NULL」 - 我強調了我不希望NULLs
「或它可以指向特定的某事記錄。」該類型定義記錄。

在我上面的回覆之上,這似乎在任何查詢中增加了復原複雜性。我的回答是基於我對你所呈現的內容的理解。我們要麼不瞭解彼此,要麼只是在我的最後。我很感激你的意見,但是我認爲這不是一個可行的解決方案。

回答

1

你應該能夠在一個MySQL觸發器來處理這個:

DELIMITER $$ 
CREATE TRIGGER before_something_update 
BEFORE UPDATE ON Something 
FOR EACH ROW BEGIN 
    IF NEW.IsObsolete = 'N' THEN 
     UPDATE Something SET IsObsolete = 'Y' WHERE SomethingId != NEW.SomethingId AND SomethingTypeID = NEW.SomethingTypeId; 
    END IF; 
DELIMITER ; 

而且在插入類似的東西。 觸發器將檢查您是否嘗試將IsObselete設置爲N,並且如果您要更新具有相同類型且不是當前行的所有行並將它們設置爲Y.

您可能會收到如果您使用的是InnoDB,則會導致死鎖問題,但我認爲您不會遇到與MyISAM有關的問題。

+0

感謝您的回覆。直到後期才能深入研究。使用MySQL,因爲你只能定義一個Trigger動作,所以我將不得不選擇動作(插入或更新)並將我可以進入的內容打包,對嗎?現在,這主要影響InnoDB表,雖然有些可能需要更改並且有可能被更改。 – enfield 2011-05-13 22:10:42

+0

@enfield是的,你是對的,你需要將你的所有規則打包到一個或其他觸發器中,InnoDB你可以避免死鎖,所以鎖定你不更新或使用後的行更新觸發器。另外(雖然我不完全確定它),但您可能還需要確保在同一個更新語句中不更新多個相同類型的項目。 – Neel 2011-05-16 08:43:32

0

如果對於給定類型只能有一個,那麼屬性爲SomethingType,而不是Something

TABLE SomethingType 
(
    SomethingTypeCode ('1','2','3')    
    ActiveId 
    Description    
    PRIMARY KEY (SomethingTypeCode) 
    Foreign Key (Something) 
); 

現在ActiveId可以NULL(表示有此SomethingType沒有非過時的東西),也可以指向特定Something記錄。

而你顯然無法在其中放置多個身份證,所以你可以保證有零或一個有效的物品。

+0

@VoteyDisciple我不確定這是我所追求的。我知道我不想要'NULL'。我也想保留兩張表之間的關係分解(標準化)。雖然你的方式是一種選擇,但如果我正確地理解了你的話,它會打破我在數據庫中所擁有的東西。 – enfield 2011-05-12 01:28:21

+0

我明白你的建議,但問題是你有什麼不規範。你有一個在功能上依賴於'SomethingTypeCode'的字段,它存儲在SomethingType表以外的地方。如果你不想要'NULL'值(即總是有一個'Something'已經過時),你可以簡單地指定'NOT NULL'列。 – VoteyDisciple 2011-05-12 12:31:19

+0

「問題是你有什麼是不正常的」。這是一個大膽的聲明,特別是因爲它是正常化的。 – enfield 2011-05-12 17:36:54