带外键的复合主键问题

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 UserUserID 只有 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".

这是因为tableShoppingCartEmailAddress的值仍然是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 个 UserID1 的用户,如果他们都有不同的电子邮件地址,他们将是有效的主键。很可能您 真正 想要的,基于您在 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).