在Alexander Kuznetsov article中,他提供了以下代码段:
CREATE TABLE dbo.Vehicles(
ID INT NOT NULL,
[Type] VARCHAR(5) NOT NULL,
CONSTRAINT Vehicles_PK PRIMARY KEY(ID),
CONSTRAINT Vehicles_UNQ_ID_Type UNIQUE(ID, [Type]),
CONSTRAINT Vehicles_CHK_ValidTypes CHECK([Type] IN ('Car', 'Truck'))
);
这个片段为我提出了一些问题。
为什么有必要在唯一约束中包含ID
和Type
?如果只有ID
是唯一的,那么两列的组合也将始终是唯一的。
此外,我知道如何设置主键并指定它在SSMS中是否唯一。但是,如何在一列上指定主键,并对列组合进行唯一约束?这会创建两个索引吗?
这是因为我试图实现类似的代码,它不会创建复合主键,我得到以下错误。所以我想更好地理解这段代码。
表'MyTable'中的列与现有的主键或UNIQUE约束不匹配。
修改
我只需在MyTable
中创建复合主键即可实现此功能。实际的表定义如下所示。再次,这是有效的。但它与上面引用的代码不同。而且我不确定如果我以另一种方式做到这一点会更好。
CREATE TABLE [dbo].[MessageThread](
[Id] [int] IDENTITY(1,1) NOT NULL,
[MessageThreadType] [int] NOT NULL,
CONSTRAINT [PK_MessageThread_1] PRIMARY KEY CLUSTERED
(
[Id] ASC,
[MessageThreadType] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[MessageThread] WITH CHECK ADD CONSTRAINT [CK_MessageThread_ValidType] CHECK (([MessageThreadType]=(2) OR [MessageThreadType]=(1)))
GO
ALTER TABLE [dbo].[MessageThread] CHECK CONSTRAINT [CK_MessageThread_ValidType]
GO
答案 0 :(得分:7)
根据我的理解,对ID,[Type]
进行唯一约束的原因是让详细信息表将ID,[Type]
称为外键。通常,父表需要对用于外键的列具有唯一约束。例如,问题中的表可以有2个详细信息表:
CREATE TABLE dbo.CARS(
....
vehicle_id INT NOT NULL,
[Type] VARCHAR(5) NOT NULL,
CONSTRAINT CAR_CHK_TYPE CHECK [Type]='Car',
CONSTRAINT CAR_FK_VEHICLE FOREIGN KEY (vehicle_id,[Type]) REFERENCES Vehincle(id,[Type]));
CREATE TABLE dbo.TRUCKS(
....
vehicle_id INT NOT NULL,
[Type] VARCHAR(5) NOT NULL,
CONSTRAINT CAR_CHK_TYPE CHECK [Type]='Truck',
CONSTRAINT CAR_FK_VEHICLE FOREIGN KEY (vehicle_id,[Type]) REFERENCES Vehincle(id,[Type]));
这种方式Cars
仅包含Car
类型的详细信息,而TRUCKS
仅包含Truck
。
这种设计用于避免多态关系,例如
CREATE TABLE dbo.VEHICLE (
...,
ref_id INT NOT NULL,
-- PK of 'master' table
ref_name VARCHAR(20) NOT NULL,
-- here we put 'truck' or 'car', so we virtually have 2 parents;
-- in this case we cannot use FK constraint, the only thing that may
-- somehow enforce the logical constraint is writing a trigger
<强>更新强>
您更新的表格定义对我来说很好。我想样本表最初是为Oracle设计的,然后移植到SQLServer。在Oracle中,该唯一约束和主键可以使用相同的索引,因此同时具有PK和Unique约束不会受到惩罚。
答案 1 :(得分:7)
1:我不确定给定模式的具体目的。但请注意,可以出于多种原因应用唯一约束,最常见的原因是:(a)强制执行唯一性;(b)为优化程序提供更多信息以作出基础决策。
2:唯一约束不会创建两个索引。它创建一个索引,其中一列作为前导键列。它强制执行两者的唯一性。因此对a,b的唯一约束可能有:
a b
---- ----
1 1
1 2
2 1
2 2
请注意,这两列都不会单独强制实现唯一性。我不是在SSMS中使用表设计器的忠实粉丝(它有大量的bug并且不支持所有功能)但是这里是如何做到的:
a)右键单击网格,然后选择Indexes/Keys...
b)使用Columns
网格中的[...]按钮选择多个列
c)将Type
更改为Unique Key
d)如果需要,更改Name
以下是已有主键的表的示例。如果我想要,我可以添加一个或多个唯一索引:
答案 2 :(得分:4)
好问题。理论上你是对的;没有理由,记录总是可以由PK唯一地识别,只要这是真的,就会始终满足唯一约束。但是,如果ID和Type在数据层的边界之外有一些关系(可能这个表是Enum的数据模型?),那么不太可能存在两个具有相同Type的不同ID,因为Type的唯一性是其他地方执行。约束还设置了一个包含ID和Type的索引,使得表格相对有效地被列组合查询。
使用“管理索引和键”选项设置唯一约束。是的,这将为主键创建索引和唯一约束,并为PK和Type的组合创建索引和唯一约束。
答案 3 :(得分:4)
我怀疑在UNIQUE约束中同时包含两列的原因与您提到的错误消息有关。 SQL Server(与其他SQL DBMS一样)有一个限制,即FOREIGN KEY约束只能引用唯一性约束定义的列集。因此,如果FOREIGN KEY约束引用了两列,那么这两列必须对它们具有唯一性约束 - 即使其他约束已经保证唯一性。这是一个毫无意义的限制,但它是标准SQL的一部分。
以下示例非常相似,并解释了为什么复合外键和嵌套唯一性约束可能有用。
答案 4 :(得分:4)
你走了:
汽车和卡车具有不同的属性,因此它们不属于一个表格。这就是为什么我有两张桌子,汽车和卡车。
然而,汽车和卡车有一些属性,例如VIN(车辆识别号码)。更重要的是,VIN是独一无二的。这就是为什么我需要一张桌子车。车辆既不能是汽车也不能是卡车,所以我必须确保不能同时输入(VIN = 123456789,Type = Car)和(VIN = 123456789,Type = Truck)。这就是我在VIN上只有PK的原因。
我必须确保车辆在汽车和卡车表中都没有相应的行。这就是我在汽车和卡车中使用Type列的原因,这就是为什么我想在子表中使用(VIN,Type)汽车和卡车引用父表Vehicle。我需要对(VIN,Type)附加唯一约束的唯一原因是:它由子表中的FK约束引用。