如何在 SQL Server 中为多对多关系建模?

akn*_*ds1 5 t-sql sql-server

我需要在 SQL Server 数据库中的两个表之间引入多对多关系,这两个表都有一个整数作为主键。这在 T-SQL 中如何最好地完成?

考虑以下两个示例表定义,它们应该存在多对多关系:

CREATE TABLE [dbo].[Authors] (
    [Id]        INT            IDENTITY (1, 1) NOT NULL,
    CONSTRAINT [PK_Versions] PRIMARY KEY CLUSTERED ([Id] ASC)
);

CREATE TABLE [dbo].[Books] (
    [Id]      INT           NOT NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);
Run Code Online (Sandbox Code Playgroud)

Stu*_*tLC 8

传统的方法是使用一个额外的many:many(连接)表,它链接到两个表:

CREATE TABLE [dbo].[AuthorsBooks] (
    -- Optionally, we can give the table its own surrogate PK
    [Id]      INT IDENTITY(1,1) NOT NULL,
    AuthorId INT NOT NULL,
    BookId INT NOT NULL,

    -- Referential Integrity
    FOREIGN KEY(AuthorId) REFERENCES Authors(Id),
    FOREIGN KEY(BookId) REFERENCES Books(Id),

    -- PK is either the surrogate ...
    PRIMARY KEY CLUSTERED ([Id] ASC)
    -- ... Or the compound key
    -- PRIMARY KEY CLUSTERED (AuthorId, BookId)
);
Run Code Online (Sandbox Code Playgroud)

一个有争议的问题是您是否希望复合键AuthorId, BookId成为主键,或者是否添加您自己的新代理 - 这通常是一种主观偏好。

需要考虑是否为 Junction 表使用复合主键或新代理键的一些要点:

  • 如果没有代理,链接到联结表的外部表将需要存储两个复合键(即需要同时保留AuthorIdBookId作为外键)。
  • 因此,新代理提供了更窄主键的潜在好处,这意味着链接到此联结表的任何表都将具有一个更窄的外键。
  • 但是,使用复合键,可以有一个优化优势,即表可以直接连接到基础表BooksAuthors表,而无需先连接到连接表。

下图希望能让复合键的情况更清晰(中间表Nationality是 的连接表PersonCountry):

复合外键

编辑

用法很简单 - 如果链接存在于 many:many 表中,则认为该关系存在。要测试是否存在,您可以通过链接表“加入”,例如

-- Find all books written by AuthorId 1234
SELECT b.* 
  FROM Books b 
  INNER JOIN AuthorsBooks ab
     ON b.Id = ab.BookId
  WHERE ab.AuthorId = 1234;
Run Code Online (Sandbox Code Playgroud)