場景
我mysql里有3個表
1.車輛信息表carInfo
字段為:
carID,主鍵
2.終端信息表terminalID
字段為:
terminalID,主鍵
3.車輛與終端的中間表car_bind_terminal
carID,外鍵
terminalID,外鍵
任務(需求)
現在需要實現車輛與終端的一對一映射,讓中間表里的carID和terminalID這兩個字段都不能重復,否則添加數據時會失敗。
比如,車輛與終端的中間表car_bind_terminal里邊有這樣一條數據,代表了車輛1號與終端1號的一對一映射。
carID terminalID
1 1
現在我想要插入分別插入3條數據,分別是(1,2)、(2,1)和(2,2)。
carID terminalID
1 1
1 2 插入失敗,因為carID與第一條重復了
2 1 插入失敗,因為terminalID與第一條重復了
2 2 插入成功,因為carID和terminalID都沒有與第一條重復
理想中的最終結果應為:
carID terminalID
1 1
2 2
行動(解決方案)
方案1:從代碼層面解決(正確方案)
添加數據時,先檢查數據在數據庫中是否重復,若沒有,則添加這條數據,否則返回添加失敗。
缺點:寫法太丑,需要對數據庫進行兩次操作。
方案2:設置成兩個唯一索引(正確方案)
思路借鑒了這個網站的一對一的中間關系表的解決方案。
將carID和terminalID設置為兩個唯一索引,我這里用的是Navicat。
因為carID和terminalID是外鍵,本來就是兩個一般索引,在這里我們只需要把這兩個索引的類型從Normal設置成Unique就好了。
優點:以后業務變更,不再是一對一,可能變成一對多或是多對多,都能靈活更改。
缺點:多了個中間表,索引數也多了。
方案3:刪掉中間表,把從表的主鍵作為主表的外鍵,並將外鍵設置成唯一索引(正確方案)
優點:比上個方案少了個中間表,索引也少一半(2變成1)。
缺點:若將來業務變更為多對多,就要大改。
方案4:設置成一個復合唯一索引(錯誤方案)
不要設置成復合唯一索引,因為它允許其中的部分字段重復。
不要像下圖這樣設置。
結果
成功解決,我用了方案2,因為改動工作量小。
總結
1.如果刪除carInfo表里的1號車,car_bind_terminal里的(1,1)數據也會跟着刪除。
2.就mysql來說(別的不清楚),設置外鍵時會自動添加一個一般索引(Navicat能看到),設置主鍵時會自動添加一個唯一索引(Navicat看不到,因為主鍵是特殊的唯一索引)。
3.復合主鍵允許其中的部分字段重復。比如復合主鍵(ID,Name),數據可以同時存在(1,張三)和(2,張三)。
參考
[數據庫實體、關系(一對一實現方式、一對多實現方式、多對多實現方式)]: