有兩種建模方法可供選擇。
首先,main_man
也必須是homie
?如果是這樣,我會在homies
表上添加一個標誌。 MySQL數據類型有點不完美,但我會使用一個布爾值,我們總是映射到一個TINYINT(1) DEFAULT NULL COMMENT 'boolean'
數據類型。
下一步是限制其值爲1
或NULL
,不允許任何其他值。不幸的是,MySQL不強制執行CHECK約束,所以如果我們希望數據庫執行這個規則,我們需要實施BEFORE INSERT/BEFORE UPDATE
觸發器來執行它。
最後,我們會增加一個UNIQUE
約束
... ON homies (bro_id, main_man)
就這樣,MySQL將只允許一個單行的1
每個bro_id
一個main_man值。
這與微軟文檔支持的NULL意義「未知」的規範模式略有偏差。在我們的實現中,我們使用NULL值表示「不,不是main_man」。允許NULL
值的主要優點是SQL(通常)和MySQL特別不認爲NULL值是另一個NULL值的「重複」。 UNIQUE約束允許具有NULL值的多行。 (我覺得有改變這種行爲的一些SQL_MODE設置,但我們千萬不要去那裏。)
得到公正的homies
這是一個main_man
...
WHERE main_man = 1
,或者更簡潔,因爲我們沒有使用零表示TRUE,如果我們確信沒有其他非零值可能存在......
WHERE main_man
另一個邏輯是非常簡單的,檢查main_man IS NULL
或MAIN_MAN <=> NULL
, ORDER BY main_man, ...
,如果要在客戶端上對其進行排序,則返回SELECT
中的main_man
列。
您可能會考慮使用MySQL ENUM
數據類型,只要我們允許NULL值,並驗證MySQL將允許並在ENUM列上強制實施UNIQUE約束。 (我從來沒有嘗試過)。
這只是幾種方法之一,但它是我過去成功使用的方法之一。
-
示範
CREATE TABLE bro
(id INT UNSIGNED NOT NULL PRIMARY KEY
) ENGINE=INNODB;
CREATE TABLE homie
(id INT UNSIGNED NOT NULL PRIMARY KEY
, bro_id INT UNSIGNED NOT NULL COMMENT 'FK ref bros.id'
, main_man TINYINT(1) DEFAULT NULL COMMENT 'boolean, 1=is the main man'
, homie_name VARCHAR(10)
) ENGINE=INNODB;
ALTER TABLE homie
ADD UNIQUE INDEX homie_UX1 (bro_id, main_man);
ALTER TABLE homie
ADD CONSTRAINT FK_homie_bro FOREIGN KEY (bro_id) REFERENCES bro (id);
TODO:添加BEFORE INSERT/BEFORE UPDATE觸發器用於main_man
列限制值。
通過添加一些行來測試此操作,並檢查給定的bro_id
我們不能有多於一個main_man
。
INSERT INTO bro (id) VALUES
(2),(3);
INSERT INTO homie (id, bro_id, main_man, homie_name) VALUES
(11, 2, NULL, 'mr.slate')
, (12, 2, 1, 'barney')
;
-- attempt to insert another main_man
INSERT INTO homie (id, bro_id, main_man, homie_name) VALUES
(13, 2, 1, 'wilma')
;
-- Error Code: 1062
-- Duplicate entry '2-1' for key 'homie_UX1'
UPDATE homie SET main_man = 1 WHERE id = 11 ;
-- Error Code: 1062
-- Duplicate entry '2-1' for key 'homie_UX1'
注:我忘了提及,作爲一個小的獎金,在homie_UX1
指數(創建強制執行UNIQUE
約束)也用於支撐外鍵,因爲bro_id是領先的列。這就是我們在添加外鍵約束之前添加索引的原因。