问题描述
我收到此错误:
引用表“User”中没有匹配的主键或候选键。
我检查了其他类似的问题,但不同的答案对我没有帮助。
我的主键设置错了吗?
我必须只引用 ShoppingCart
表中的一个主键吗?
CREATE TABLE [User]
(
EmailAddress NVARCHAR(320),UserId INT IDENTITY(1,1),UserPassword VARCHAR(16),FirstName VARCHAR(256) NOT NULL,LastName VARCHAR(256) NOT NULL,MobileNumber BIGINT,PRIMARY KEY (EmailAddress,UserId)
)
CREATE TABLE [ShoppingCart]
(
OrderId INT PRIMARY KEY IDENTITY(1,UserId INT FOREIGN KEY REFERENCES [User](UserId),//-- error here
CreatedDate NVARCHAR(40)
)
非常感谢所有在下面回答我的用户。
解决方法
正如我在评论中提到的,问题在于您正在尝试创建一个 FOREIGN KEY
来引用您的表 PRIMARY KEY
中的 UNIQUE CONSTRAINT
/User
由 UserID
和 only UserID
组成;不存在这样的约束,因此 FOREIGN KEY
的创建失败。
要从字面上解决这个问题,您需要将 EmailAddress
列添加到 ShoppingCart
表和 FOREIGN KEY
的定义:
CREATE TABLE dbo.[User]
(
EmailAddress NVARCHAR(320),UserId INT IDENTITY(1,1),UserPassword VARCHAR(16),FirstName VARCHAR(256) NOT NULL,LastName VARCHAR(256) NOT NULL,MobileNumber varchar(20),--Numerical data types are a poor choice for a Phone Number
PRIMARY KEY (EmailAddress,UserId)
)
CREATE TABLE dbo.[ShoppingCart]
(
OrderId INT PRIMARY KEY IDENTITY(1,UserId INT,EmailAddress nvarchar(320),CreatedDate datetime2(0),--(n)varchar is not a "one size fits all" data type.
FOREIGN KEY (EmailAddress,UserID) REFERENCES [User](EmailAddress,UserId)
)
事实上,这是一个坏主意,因为如果有人更改了他们的电子邮件地址,您认为会发生什么?好吧,让我们试试。首先,让我们创建一些示例数据:
INSERT INTO dbo.[User] (EmailAddress,FirstName,LastName)
VALUES(N'Jane@bloggs.com','Jane','Bloggs');
INSERT INTO dbo.ShoppingCart (UserId,EmailAddress,CreatedDate)
VALUES(1,N'Jane@bloggs',GETDATE());
现在假设 Jane 更改了她的电子邮件地址,因此我们尝试UPDATE
表格:
UPDATE dbo.[User]
SET EmailAddress = N'Jane.Bloggs@email.com'
WHERE UserId = 1;
INSERT 语句与 FOREIGN KEY 约束“FK__ShoppingCart__36DDA17A”冲突。数据库“Sandbox”,表“dbo.User”发生冲突。
这是因为表EmailAddress
中ShoppingCart
的值仍然是N'Jane@bloggs.com'
,所以无法更新该值。显然,您也不能UPDATE
dbo.ShopppingCart
中的值,因为您会得到相同的错误:
UPDATE dbo.[ShoppingCart]
SET EmailAddress = N'Jane.Bloggs@email.com'
WHERE UserId = 1;
INSERT 语句与 FOREIGN KEY 约束“FK__ShoppingCart__415B2FED”冲突。数据库“Sandbox”,表“dbo.User”发生冲突。
那你会怎么做呢?好吧,我假设电子邮件地址在应用程序中是唯一的,不是用户。目前,您可以有 100 个用户的 UserID
为 1
,并且如果他们都有不同的电子邮件地址,它们将是有效的主键。很可能您真正想要的是,基于您不希望表 EmailAddress
中的 ShoppingCard
,UserID
是主键,并且电子邮件地址具有单独的唯一约束。这将为您提供以下内容:
CREATE TABLE dbo.[User] -- I recommend against the name USER,it's a reserved keyword
(
EmailAddress NVARCHAR(320),--Numerical data types are a poor choice for a Phone Number
);
ALTER TABLE dbo.[User] ADD CONSTRAINT PK_User PRIMARY KEY (UserId);
ALTER TABLE dbo.[User] ADD CONSTRAINT UQ_UserEmail UNIQUE (EmailAddress);
GO
CREATE TABLE dbo.[ShoppingCart]
(
OrderId INT IDENTITY(1,--(n)varchar is not a "one size fits all" data type.
)
ALTER TABLE dbo.[ShoppingCart] ADD CONSTRAINT PK_ShoppingCart PRIMARY KEY (OrderId);
ALTER TABLE dbo.[ShoppingCart] ADD CONSTRAINT FK_ShoppingCart_User
FOREIGN KEY (UserId)
REFERENCES dbo.[User] (UserID);
我还为您的约束提供了明确的名称,这是您真的应该养成的习惯。
现在您可以毫无问题地INSERT
示例数据和UPDATE
电子邮件地址:
INSERT INTO dbo.[User] (EmailAddress,GETDATE());
GO
UPDATE dbo.[User]
SET EmailAddress = N'Jane.Bloggs@email.com'
WHERE UserId = 1;
如果您尝试添加具有相同电子邮件地址的其他用户,则会出现错误:
INSERT INTO dbo.[User] (EmailAddress,LastName)
VALUES(N'Jane.Bloggs@email.com','Bloggs');
违反 UNIQUE KEY 约束“UQ_UserEmail”。无法在对象“dbo.User”中插入重复键。重复的键值为 (Jane.Bloggs@email.com)。