【问题标题】:For a composite foreign key, is a/why is a composite UNIQUE constraint in the referenced table required for a column combination with a primary key?对于复合外键,与主键的列组合是否需要/为什么引用表中的复合 UNIQUE 约束?
【发布时间】:2016-11-06 02:10:28
【问题描述】:

我有一个关于明确定义某事物的独特性的问题。这与复合外键的创建有关。我在下面创建了一个示例,以尝试使我的问题尽可能清晰(为了便于测试,我添加了一些数据插入)。

[Table1] 的每个条目都必须有一个唯一的 [Name]

CREATE TABLE [Table1]
(
    [ID]    INT IDENTITY            NOT NULL PRIMARY KEY,
    [Name]  NVARCHAR(255) UNIQUE    NOT NULL CHECK(LTRIM(RTRIM([Name])) <> '')
);

INSERT INTO [Table1]([Name])
VALUES
('Name 1'),
('Name 2'),
('Name 3'),
('Name 4'),
('Name 5'),
('Name 6'),
('Name 7')

[Table2] 中的每个 [Value] 对于每个 [Table1ID] 都必须是唯一的。

CREATE TABLE [Table2]
(
    [ID]        INT IDENTITY    NOT NULL    PRIMARY KEY,
    [Table1ID]  INT             NOT NULL    FOREIGN KEY REFERENCES [Table1]([ID]),
    [Value]     NVARCHAR(255)   NOT NULL    CHECK(LTRIM(RTRIM([Value])) <> ''),

    --UNIQUE([ID], [Table1ID]),
    UNIQUE([Table1ID], [Value])
);

INSERT INTO [Table2]([Table1ID], [Value])
VALUES
(1, 'Entry 1'),
(1, 'Entry 2'),
(1, 'Entry 3'),
(1, 'Entry 4'),
(3, 'Entry 5'),
(3, 'Entry 6'),
(3, 'Entry 7')

[Table3][Table1ID][Table2ID] 的每个组合必须在 [Table2] 中具有匹配的组合(我假设 [Table1ID][Table2ID] 的两个 FOREIGN KEYs 是多余的,如果复合FOREIGN KEY 到位了吗?)。

CREATE TABLE [Table3]
(
    [ID]        INT IDENTITY    NOT NULL,
    [Table1ID]  INT             NOT NULL    FOREIGN KEY REFERENCES [Table1]([ID]),
    [Table2ID]  INT             NOT NULL    FOREIGN KEY REFERENCES [Table2]([ID]),

    FOREIGN KEY ([Table2ID], [Table1ID]) REFERENCES [Table2](ID, [Table1ID])
);

INSERT INTO [Table3]([Table2ID], [Table1ID])
VALUES
(5, 3)

[Table3] 中的复合 FOREIGN KEY 约束是问题所在。如果[Table2] 中注释掉的UNIQUE 约束未注释,则可以成功创建[Table3]。如果不是,[Table3] 的创建将失败,并显示“引用的表中没有与外键中的引用列列表匹配的主键或候选键”。

我了解键的唯一性需要,但是由于[Table2][ID] 列是PRIMARY KEY 并且始终是唯一的,为什么[Table1ID] 列在[Table2] 中不是唯一的防止[Table2][ID][Table1ID] 的任意组合是唯一的?

基本上,UNIQUE([ID], [Table1ID]) 部分对我来说似乎是多余的,但似乎必须明确定义 [Table2][Table1ID] 的唯一性,以便 SQL Server 允许在 @ 中创建复合外键987654354@.

真的是这样吗?为了允许上述情况,需要这种约束,无论它看起来多么多余?还是我错过了什么?

【问题讨论】:

  • 是的,因为您发现必须声明唯一性。我会质疑任何需要做你所要求的数据设计。
  • 再一次,我把上面的东西放在一起作为例子来演示一下。您能否扩展您的数据设计评论?
  • 让我直说。 Table2 已经与 Table1 有关系。在表 3 中,希望直接在 1 和 2 之间创建关系,同时尊重 2 与 1 的现有关系。您是否能够针对这种关系扩展任何合理的业务需求?
  • @Paparazzi [Table1]是key的列表,比如列表的名字,[Table2]是每个key的可选值的列表,即列表中的值, [Table3] 是从此类列表中选择的值。不同的用户可以选择不同的值(因此第三个表存储他们的选择),但每个人都可以从相同的值列表中进行选择 ([Table2])。 [Table1] 引用最初可能看起来是多余的,但实际上它提供了一些数据完整性。
  • 如果有人决定更改 [Table2] 记录以使其引用不同的 [Table1] 记录(即将可选值移动到不同的列表),但 [Table3] 中的记录已经在引用因为一个或多个用户已经在原始键下选择了该列表值,所以将阻止更改。如果没有额外的 [Table1] 引用,用户最初选择的值将隐式移动到不同的列表。

标签: sql-server tsql foreign-keys unique-constraint


【解决方案1】:

实际上,这更多地与关系数据库的理论方面有关。

在其父表中引用的外键不是一组任意的列,无论它们多么独特;它引用一个键 - 主键或备用键。并且这个键必须明确声明。

【讨论】:

  • 并且引用表中的UNIQUE 约束算作组合FOREIGN KEY 约束的可引用键?
  • @Interminable,是的-从学术上讲,它是备用键。您可能会感到惊讶,但在 SQL Server 中,即使是唯一索引也可以作为引用键(但不确定过滤索引)。
  • @philipxy,我认​​为数据库在这里采用“比抱歉更安全”的策略。你看,当你引用一个键时,它不能再被删除了。但是,如果仅将列的子集声明为键,则数据库引擎将不得不做太多工作来确定是否应该允许您从父表中删除特定键。此外,这种规则弯曲所产生的歧义程度将是灾难性的,imo。
  • 您会说[Table3][Table1][Table2] 中的两个FOREIGN KEY 约束对于复合外键来说是多余的吗?或者是否值得将FOREIGN KEY 保留为[Table1],否则[Table3] 将没有“直接”连接?还是说没有意义?
  • @Interminable,在大多数 OLTP 系统中,您首先不需要“直接”Table3 -> Table1 引用。您的架构看起来更像一个临时数据库,而不是可操作的。您可以通过完全删除 Table3.Table1ID 列来避免非规范化,而不会破坏任何完整性或唯一性。而当你需要它的价值时,你可以随时从Table2获取它。
【解决方案2】:

唯一列集的任何超集都是唯一的。 DBMS 可以通过编程来理解这一点。但是 SQL 要求您在引用的表中声明该组合是唯一的。

PS 在关系模型中,外键必须引用候选键,这两者都必须声明。但是在 SQL 中,UNIQUE 声明了一个超键,而 FOREIGN KEY 声明了一个外部超键。 (当一个超键不包含更小的超键时,它是一个候选键。)为了符合人体工程学的冗余,人们可能更喜欢外部超键声明的目标具有显式匹配的唯一声明。但没有理论或实施理由。

【讨论】:

    猜你喜欢
    • 2022-11-21
    • 2015-06-23
    • 2011-01-23
    • 2013-11-11
    • 2011-02-07
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多