Sql server 对于复合外键,与主键的列组合是否需要引用表中的复合唯一约束?

Sql server 对于复合外键,与主键的列组合是否需要引用表中的复合唯一约束?,sql-server,tsql,foreign-keys,unique-constraint,Sql Server,Tsql,Foreign Keys,Unique Constraint,我有一个关于明确定义事物唯一性的问题。这与创建复合外键有关。我在下面创建了一个示例,试图让我的问题尽可能清楚(为了便于测试,我添加了一些数据插入) [Table1]的每个条目必须具有唯一的[Name] CREATE TABLE [Table1] ( [ID] INT IDENTITY NOT NULL PRIMARY KEY, [Name] NVARCHAR(255) UNIQUE NOT NULL CHECK(LTRIM(RTRIM([Nam

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

[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')
[Table3]
中的
[Table1ID]
[Table2ID]
的每个组合必须在
[Table2]
中有一个匹配的组合(我假设
[Table1ID]
[Table2ID]
的两个
外键
如果组合的
外键
已经就位,那么这两个
外键就多余了?)

问题在于
[表3]
中的复合
外键
约束。如果在
[Table2]
中注释掉的
唯一
约束未注释,则可以成功创建
[Table3]
。如果不是,则创建
[Table3]
将失败,说明“引用的表中没有与外键中的引用列列表匹配的主键或候选键”

我理解对键的唯一性的需要,但是由于
[Table2]
[ID]
列是
主键
并且总是唯一的,为什么
[Table1ID]
列在
[Table2]
中不是唯一的,会阻止
[ID]
[Table1ID]的任何组合
[Table2]
中的
是唯一的吗

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


真的是这样吗?这一约束,无论看起来多么多余,都是为了实现上述目标所必需的?还是我遗漏了什么?

实际上,更多的是关系数据库的理论方面


其父表中的外键引用不是任意的列集合,不管它们是多么独特;它引用一个键-主键或备用键。并且必须清楚地声明此键。

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


PS在关系模型中,外键必须引用候选键,候选键必须同时声明。但在SQL中,UNIQUE声明了一个超键,而FOREIGN KEY声明了一个外部超键。(当一个超键不包含更小的超键时,它是一个候选键。)为了实现人机工程学冗余,人们可能更希望外部超键声明的目标具有明确的匹配唯一声明。但是没有理论上或实现上的理由。

并且引用表中的
UNIQUE
约束对于复合
外键
约束而言被视为可引用键?@没完没了,是的-从学术上讲,它是一个备用键。您可能会感到惊讶,但在SQL Server中,即使是唯一的索引也可以充当引用键(不过,不确定筛选的索引)。@philipxy,我认为数据库在这里采用了“安全比抱歉更好”的策略。你看,当你引用一个键时,它不能再被删除了。但是,如果只将列的子集声明为键,那么数据库引擎将不得不做太多的工作,试图弄清楚它是否应该允许您从父表中删除特定的键。此外,在国际海事组织,由于这种规则弯曲而产生的模糊程度将是灾难性的。您认为
[Table3]
[Table1]
[Table2]
中的两个
外键
约束对于复合外键来说是多余的吗?或者将
外键
保留到
[Table1]
是否值得,否则就不会有来自
[Table3]
的“直接”连接?或者这是没有意义的?@没完没了的,在大多数OLTP系统中,您首先不需要“直接”
Table3
->
Table1
引用。您的模式看起来更像一个临时数据库,而不是一个可操作的数据库。通过完全删除
Table3.Table1ID
列而不破坏任何完整性或唯一性,可以避免非规范化。当您需要它的值时,您总是可以从
表2
中获取它。是的,因为您发现必须声明唯一性。我会质疑任何需要按照您的要求进行的数据设计。你能对你的数据设计评论进行扩展吗?让我直说吧。表2已经与表1有关系。在表3中,我们希望在1和2之间直接创建一个关系,同时尊重2与1之间先前存在的关系。您是否能够扩展该类型关系的任何理性业务需求?@Paparazzi[
Table1
]是一个键列表,例如列表的名称,
[Table2]
是每个键的可选值列表,即列表中的值,
[Table3]
是从该列表中选择的值。不同的用户可以选择不同的值(因此第三个表存储了他们的选择),但每个人都可以从相同的值列表中进行选择(
[Table2]
)。[
Table1
]引用最初可能看起来是多余的,但实际上它提供了一些数据完整性。如果有人决定更改
[Table2]
记录,使其引用不同的
[Table1]
记录(即将可选值移动到
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')
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)