5

我需要在 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)
);
4

1 回答 1

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)
);

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

要考虑是否为联结表选择复合主键或新代理键的一些要点:

  • 如果没有代理项,链接到联结表的外部表将需要存储两个复合键(即需要同时保留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;
于 2012-12-20T11:00:12.690 回答