Database-Design
強制執行“至少一個”關係
多對多(數據模型)維基百科文章使用了作者和書籍的例子:
例如,將 A 視為作者,將 B 視為書籍。一個作者可以寫幾本書,而一本書可以由幾個作者寫。
在關係數據庫管理系統中,這種關係通常通過關聯表(也稱為交叉引用表)來實現,例如,AB 具有兩個一對多關係 A -> AB 和 B -> AB。在這種情況下,AB 的邏輯主鍵由兩個外鍵(即 A 和 B 的主鍵的副本)形成。
有了約束,你將如何強制一本書必須****至少有一個作者?
筆記:
- 對於此範例,沒有“主要”作者之類的東西。
- 用 SQL(任何 RDBMS)或一般術語回答。
如何在 SQL 中執行此操作,僅使用 DDL(
FOREIGN KEY
和UNIQUE
約束):CREATE TABLE author ( author_id INT NOT NULL, author_name VARCHAR(100), CONSTRAINT author_pk PRIMARY KEY (author_id) ) ; CREATE TABLE book ( book_id INT NOT NULL, book_title VARCHAR(100), CONSTRAINT book_pk PRIMARY KEY (book_id) ) ; CREATE TABLE book_author ( book_id INT NOT NULL, author_id INT NOT NULL, CONSTRAINT book_author_pk PRIMARY KEY (book_id, author_id), CONSTRAINT book__book_author_fk FOREIGN KEY (book_id) REFERENCES book (book_id), CONSTRAINT author__book_author_fk FOREIGN KEY (author_id) REFERENCES author (author_id) ) ;
到目前為止,這僅在書籍和作者之間實現了常見的多對多關係。這意味著一本書可以有 0、1 或多個作者,而一個作者可以有 0、1 或多本書。
如果我們想要嚴格的*“一本書必須****至少有 1 個作者”*,我們可以在其中添加另一列
book
和附加約束:ALTER TABLE book ADD COLUMN author_id INT NOT NULL, ADD CONSTRAINT book_must_have_at_least_1_author_fk FOREIGN KEY (book_id, author_id) REFERENCES book_author (book_id, author_id) ;
筆記:
為了使上述約束起作用,我們需要一個已經實現可延遲約束(例如 Postgres、Oracle)或可以在一個語句中插入/刪除多個表(Postgres)的 DBMS。如果沒有這些,我們可以放寬一些限制,例如通過 3 個步驟來解除
NOT NULL
和book (author_id)
插入(比如一本新書):
- 插入書中(author_id 為空)
- 插入 book_author
- 更新書籍(相應地設置 author_id)。然後我們可以將上述步驟包裝在事務/過程中,然後僅通過這些事務/過程限制對錶的訪問(每個操作一個過程,插入新書及其作者,刪除書籍及其作者,更新作者,刪除作者從書等)。
如果不是很明顯,這些程序可能會變得有點複雜,例如當必須刪除一本書的“主要”作者時,因為該程序必須搜尋其餘作者並
book.author_id
相應更新或失敗/拒絕刪除,如果沒有其他作者離開了。
- 另一種選擇——因為我們提到了程序——是從一開始就將它們用於所有插入/更新/刪除操作。如果設計和測試正確,它們可以強制執行所有約束,允許不聲明任何外鍵。