[英]MySQL Database design. Inserting rows in 1to1 tables.
將行插入到相互引用 1 到 1 的表中的最佳方法是什么?
我的意思是,在 MySQL 5.5 和 InnoDB 表中,我有一個類似於以下的數據庫設計
當我們嘗試在 table1 和 table2 中插入行時,就會出現問題。 由於 MySQL 中沒有多表插入,因此我無法插入行,因為外鍵不是兩個表中的 NULL 字段,應該同時插入兩個表中。
解決這個問題的最佳方法是什么?
我想到了 3 種可能的解決方案,但我想知道是否還有更多,或者哪個是最好的以及為什么。
將外鍵字段設置為NULLABLE,在表中插入一行后,插入另一行,然后更新第一個。
如上所示,但具有特殊值,例如 -1。 首先,插入一個外key = -1
的表,相當於 NULL 但避免將該字段設置為 NULLABLE。 之后,我們在另一個表中插入行並更新插入的第一個。
在兩者之間創建一個關系表,盡管它並不是真正必要的,因為它是 1 比 1 的比率
謝謝!!
編輯我簡要解釋了我需要這種循環關系:它是從父表到其子表的非規范化。 總是從父表中獲得排名最高的孩子的參考是為了高性能的順序。
我會回答這個問題,因為我覺得這是一個設計缺陷。
首先,如果兩張桌子是真正的1:1
關系,為什么不只有一張桌子?
其次,如果這不是真正的1:1
關系而是超類型-子類型問題,那么您也不需要這種循環外鍵。 假設table1
是Employee
並且table2
是Customer
。 當然,大多數客戶不是員工(反之亦然)。 但有時客戶也可能是員工。 這可以通過 3 個表來解決:
Person
------
id
PRIMARY KEY: id
Employee
--------
personid
lastname
firstname
... other data
PRIMARY KEY: personid
FOREIGN KEY: personid
REFERENCES Person(id)
Customer
--------
personid
creditCardNumber
... other data
PRIMARY KEY: personid
FOREIGN KEY: personid
REFERENCES Person(id)
在您描述的場景中,您有兩個表Parent
和Child
具有1:N
關系。 然后,您想以某種方式為每個父母存儲表現最佳(基於定義的計算)的孩子。
這會工作嗎?:
Parent
------
id
PRIMARY KEY: id
Child
-----
id
parentid
... other data
PRIMARY KEY: id
FOREIGN KEY: parentid
REFERENCES Parent(id)
UNIQUE KEY: (id, parentid) --- needed for the FK below
BestChild
---------
parentid
childid
... other data
PRIMARY KEY: parentid
FOREIGN KEY: (childid, parentid)
REFERENCES Child(id, parentid)
這樣,您可以強制執行所需的引用完整性(每個 BestChild 都是一個 Child,每個 Parent 都只有一個 BestChild)並且引用中沒有循環路徑。 對最佳子項的引用存儲在額外表中,而不是Parent
表中。
您可以通過加入為每位家長找到 BestChild:
Parent
JOIN BestChild
ON Parent.id = BestChild.parentid
JOIN Child
ON BestChild.childid = Child.id
此外,如果您想為多個性能測試(針對不同類型的測試或不同日期的測試)存儲最佳子項,您可以添加一個test
字段,並將主鍵更改為(test, parentid)
:
BestChild
---------
testid
parentid
childid
... other data
PRIMARY KEY: (testid, parentid)
FOREIGN KEY: (childid, parentid)
REFERENCES Child(id, parentid)
FOREIGN KEY: testid
REFERENCES Test(id)
我會創建一個黑洞表並在其上放置一個觸發器來處理插入
CREATE TABLE bh_table12 (
table1col varchar(45) not null,
table2col varchar(45) not null
) ENGINE = BLACKHOLE
並在其上觸發以處理插入
DELIMITER $$
CREATE TRIGGER ai_bh_table12_each AFTER INSERT ON bh_table12 FOR EACH ROW
BEGIN
DECLARE mytable1id integer;
DECLARE mytable2id integer;
SET foreign_key_checks = 0;
INSERT INTO table1 (table1col, table2_id) VALUES (new.table1col, 0);
SELECT last_insert_id() INTO mytable1id;
INSERT INTO table2 (table2col, table1_id) VALUES (new.table2col, table1id);
SELECT last_insert_id() INTO mytable2id;
UPDATE table1 SET table2_id = mytable2id WHERE table1.id = mytable1id;
SET foreign_key_checks = 1;
END $$
DELIMITER ;
請注意,觸發器中的操作是一個事務的一部分(使用 InnoDB 或類似情況時),因此觸發器中的錯誤將回滾部分更改。
注意你的表結構
請注意,如果是 1-on-1 表,則只需在 table1 中放入 table2_id,在 table2 中不要放入 table1_id(反之亦然)。
如果您需要根據 table2 查詢 table1,您可以使用:
SELECT table1.* FROM table1
INNER JOIN table2 on (table2.id = table1.table2_id)
WHERE table2.table2col = 'test2'
反過來也一樣
SELECT table2.* FROM table2
INNER JOIN table1 on (table2.id = table1.table2_id)
WHERE table1.table1col = 'test1'
鏈接:
http://dev.mysql.com/doc/refman/5.1/en/blackhole-storage-engine.html
http://dev.mysql.com/doc/refman/5.1/en/triggers.html
我覺得這是一個重要的問題,在整個 web 中我還沒有找到任何 100% 令人滿意的答案。 您給出的 2 個答案是我找到的最好的答案,但它們並非 100% 令人滿意。
原因如下:
我想 Emilio 不能將他最好的孩子放在他的 parent 表中的原因很簡單,因為我有同樣的問題:不是每個孩子都會被標記為父母最好的孩子。 所以他仍然需要將其他孩子的信息存儲在其他地方。 在這種情況下,他會在他們的父母的表中獲得一些關於最好孩子的信息,而其他孩子則在一個單獨的數據庫中。 這是一個巨大的混亂。 例如,他想更改關於children的數據結構的那一天,他需要在兩個表中都進行更改。 每次他對所有孩子編寫查詢時,他都應該查詢兩個表,等等......
Emilio 不能只將最佳子外鍵設置為可為空的原因(我認為 Emilio,但對我來說會非常嚴格),因為他需要確保父母總是有一個最好的孩子。 在 Emilio 的情況下,這可能不太容易想象,但在我的情況下,我不能擁有相當於父母沒有孩子的情況。
因此,我傾向於認為將 foreign_key_checks 設置為零的解決方案是最好的,但問題是:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.