强制执行“至少一个”关系

Ste*_*ven 8 normalization database-design constraint

许多一对多(数据模型)维基百科的文章使用作者和图书的例子:

例如,将 A 视为作者,将 B 视为书籍。一个作者可以写几本书,一本书可以由几个作者写。

在关系数据库管理系统中,这种关系通常是通过关联表(也称为交叉引用表)来实现的,例如,AB 具有两个一对多关系 A -> AB 和 B -> AB。在这种情况下,AB 的逻辑主键由两个外键(即 A 和 B 的主键的副本)形成。

有了约束,你会如何执行一本书必须至少一个作者?

笔记:

  • 对于此示例,本书没有“主要”作者这样的东西。
  • 以 SQL(任何 RDBMS)或一般术语回答。

ype*_*eᵀᴹ 8

如何在 SQL 中仅使用 DDL(FOREIGN KEYUNIQUE约束)执行此操作:

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)
) ;
Run Code Online (Sandbox Code Playgroud)

到目前为止,这仅实现了书籍和作者之间常见的多对多关系。这意味着一本书可以有 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) ;
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 为了使上述约束发挥作用,我们需要一个已实现可延迟约束的 DBMS(例如 Postgres、Oracle),或者可以在一个语句中向多个表插入/删除(Postgres)。如果没有这些,我们可以放宽一些限制,例如分三步解除NOT NULLfrom和插入(比如一本新书):book (author_id)

    • 插入书中(author_id 为空)
    • 插入 book_author
    • 更新书籍(相应地设置author_id)。

    然后,我们可以将上述步骤包装在事务/过程中,然后仅通过这些事务/过程限制对表的访问(每个操作一个过程,插入新书及其作者,删除书籍及其作者,更新作者,删除作者)来自书本等)。

    如果不是完全明显,这些过程可能会变得有点复杂,例如,当必须删除一本书的“主要”作者时,因为该过程必须搜索其余作者并相应更新,book.author_id或者如果没有,则失败/拒绝删除其他作者离开了。

  • 另一个选择 - 因为我们提到了过程 - 是从一开始就将它们用于所有插入/更新/删除操作。如果设计和测试正确,它们可以强制执行所有约束,允许不声明任何外键。