带外键的复合主键问题
Compound primary key issue with foreign key
我收到这个错误:
There are no primary or candidate keys in referenced table 'User' that match.
我检查了其他类似的问题,但不同的答案对我没有帮助。
我的主键设置有误吗?
我必须只引用 ShoppingCart
table 中的一个主键吗?
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,1),
UserId INT FOREIGN KEY REFERENCES [User](UserId), //-- error here
CreatedDate NVARCHAR(40)
)
非常感谢所有在下面回答我的用户。
正如我在评论中提到的,问题是您正在尝试创建一个 FOREIGN KEY
,它在您的 table User
由 UserID
和 只有 UserID
组成;不存在这样的约束,因此 FOREIGN KEY
的创建失败。
要从字面上解决这个问题,您需要将 EmailAddress
列添加到 ShoppingCart
table 和 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,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
table:
UPDATE dbo.[User]
SET EmailAddress = N'Jane.Bloggs@email.com'
WHERE UserId = 1;
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__ShoppingCart__36DDA17A". The conflict occurred in database "Sandbox", table "dbo.User".
这是因为tableShoppingCart
中EmailAddress
的值仍然是N'Jane@bloggs.com'
,所以无法更新该值。显然,你不能也 UPDATE
dbo.ShopppingCart
中的值,因为你会得到同样的错误:
UPDATE dbo.[ShoppingCart]
SET EmailAddress = N'Jane.Bloggs@email.com'
WHERE UserId = 1;
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__ShoppingCart__415B2FED". The conflict occurred in database "Sandbox", table "dbo.User".
那么你会怎么做呢?好吧,我假设电子邮件地址在应用程序中是唯一的,不是用户。目前,您可以有 100 个 UserID
为 1
的用户,如果他们都有不同的电子邮件地址,他们将是有效的主键。很可能您 真正 想要的,基于您在 table ShoppingCard
中不想要 EmailAddress
的是 UserID
作为主键,电子邮件地址具有单独的唯一约束。这会为您提供以下内容:
CREATE TABLE dbo.[User] -- I recommend against the name USER, it's a reserved keyword
(
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
);
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,1),
UserId INT,
CreatedDate datetime2(0), --(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, FirstName, LastName)
VALUES(N'Jane@bloggs.com','Jane','Bloggs');
INSERT INTO dbo.ShoppingCart (UserId, CreatedDate)
VALUES(1,GETDATE());
GO
UPDATE dbo.[User]
SET EmailAddress = N'Jane.Bloggs@email.com'
WHERE UserId = 1;
如果您尝试添加具有相同电子邮件地址的其他用户,则会出现错误:
INSERT INTO dbo.[User] (EmailAddress, FirstName, LastName)
VALUES(N'Jane.Bloggs@email.com','Jane','Bloggs');
Violation of UNIQUE KEY constraint 'UQ_UserEmail'. Cannot insert duplicate key in object 'dbo.User'. The duplicate key value is (Jane.Bloggs@email.com).
我收到这个错误:
There are no primary or candidate keys in referenced table 'User' that match.
我检查了其他类似的问题,但不同的答案对我没有帮助。
我的主键设置有误吗?
我必须只引用 ShoppingCart
table 中的一个主键吗?
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,1),
UserId INT FOREIGN KEY REFERENCES [User](UserId), //-- error here
CreatedDate NVARCHAR(40)
)
非常感谢所有在下面回答我的用户。
正如我在评论中提到的,问题是您正在尝试创建一个 FOREIGN KEY
,它在您的 table User
由 UserID
和 只有 UserID
组成;不存在这样的约束,因此 FOREIGN KEY
的创建失败。
要从字面上解决这个问题,您需要将 EmailAddress
列添加到 ShoppingCart
table 和 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,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
table:
UPDATE dbo.[User]
SET EmailAddress = N'Jane.Bloggs@email.com'
WHERE UserId = 1;
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__ShoppingCart__36DDA17A". The conflict occurred in database "Sandbox", table "dbo.User".
这是因为tableShoppingCart
中EmailAddress
的值仍然是N'Jane@bloggs.com'
,所以无法更新该值。显然,你不能也 UPDATE
dbo.ShopppingCart
中的值,因为你会得到同样的错误:
UPDATE dbo.[ShoppingCart]
SET EmailAddress = N'Jane.Bloggs@email.com'
WHERE UserId = 1;
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__ShoppingCart__415B2FED". The conflict occurred in database "Sandbox", table "dbo.User".
那么你会怎么做呢?好吧,我假设电子邮件地址在应用程序中是唯一的,不是用户。目前,您可以有 100 个 UserID
为 1
的用户,如果他们都有不同的电子邮件地址,他们将是有效的主键。很可能您 真正 想要的,基于您在 table ShoppingCard
中不想要 EmailAddress
的是 UserID
作为主键,电子邮件地址具有单独的唯一约束。这会为您提供以下内容:
CREATE TABLE dbo.[User] -- I recommend against the name USER, it's a reserved keyword
(
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
);
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,1),
UserId INT,
CreatedDate datetime2(0), --(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, FirstName, LastName)
VALUES(N'Jane@bloggs.com','Jane','Bloggs');
INSERT INTO dbo.ShoppingCart (UserId, CreatedDate)
VALUES(1,GETDATE());
GO
UPDATE dbo.[User]
SET EmailAddress = N'Jane.Bloggs@email.com'
WHERE UserId = 1;
如果您尝试添加具有相同电子邮件地址的其他用户,则会出现错误:
INSERT INTO dbo.[User] (EmailAddress, FirstName, LastName)
VALUES(N'Jane.Bloggs@email.com','Jane','Bloggs');
Violation of UNIQUE KEY constraint 'UQ_UserEmail'. Cannot insert duplicate key in object 'dbo.User'. The duplicate key value is (Jane.Bloggs@email.com).