简体   繁体   English

外键复合主键问题

[英]Compound primary key issue with foreign key

I'm getting this error:我收到此错误:

There are no primary or candidate keys in referenced table 'User' that match.引用的表“用户”中没有匹配的主键或候选键。

I checked for other similar questions but different answers didn't help me.我检查了其他类似的问题,但不同的答案对我没有帮助。

Are my primary keys set wrong?我的主键设置错了吗?
Must I reference only one primary key in ShoppingCart table ?我必须在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,1),
    UserId INT FOREIGN KEY REFERENCES [User](UserId), //-- error here
    CreatedDate NVARCHAR(40)
)

Thank you very much for all the users who answer me below.非常感谢所有在下面回答我的用户。

As I have mentioned in the comments, the problem is that you are trying to create a FOREIGN KEY that references a PRIMARY KEY / UNIQUE CONSTRAINT in your table User which is made up of UserID and only UserID ;正如我在评论中提到的,问题是您正在尝试创建一个FOREIGN KEY来引用您的表UserPRIMARY KEY / UNIQUE CONSTRAINT ,它由UserID只有UserID no such constraint exists and as such the creation of the FOREIGN KEY fails.不存在这样的约束,因此创建FOREIGN KEY失败。

To address this literally, you would need to add the EmailAddress column to the ShoppingCart table and the FOREIGN KEY 's definition:为了从字面上解决这个问题,您需要将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,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)
)

This, in truth, is a bad idea, as what do you think would happen if someone changed their email address?事实上,这是一个坏主意,因为如果有人更改了他们的电子邮件地址,您认为会发生什么? Well, let's try.好吧,让我们试试。 Firstly, let's create some sample data:首先,让我们创建一些示例数据:

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());

And now Let's say Jane has changed her Email address, so we try to UPDATE the table:现在假设 Jane 更改了她的电子邮件地址,因此我们尝试UPDATE表:

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". INSERT 语句与 FOREIGN KEY 约束“FK__ShoppingCart__36DDA17A”冲突。 The conflict occurred in database "Sandbox", table "dbo.User".冲突发生在数据库“Sandbox”、表“dbo.User”中。

This is because the value of EmailAddress in the table ShoppingCart is still N'Jane@bloggs.com' , so the value can't be updated.这是因为表ShoppingCartEmailAddress的值仍然是N'Jane@bloggs.com' ,所以该值无法更新。 Obviously, you can't also UPDATE the value in dbo.ShopppingCart because you'll get the same error:显然,你也不能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". INSERT 语句与 FOREIGN KEY 约束“FK__ShoppingCart__415B2FED”冲突。 The conflict occurred in database "Sandbox", table "dbo.User".冲突发生在数据库“Sandbox”、表“dbo.User”中。

So what do you do instead?那么你会怎么做呢? Well I assume that the email address is meant to be unique within the application, not by user.好吧,我假设电子邮件地址在应用程序中是唯一的,而不是用户。 At the moment you could have 100 Users with a UserID of 1 and provided they all had different Email Addresses, they would be valid Primary Keys.目前,您可以拥有 100 个用户UserID1UserID ,并且如果他们都有不同的电子邮件地址,则它们将是有效的主键。 Most likely what you really want, based on that you don't want EmailAddress in the table ShoppingCard , is for UserID to be the Primary Key, and the Email Address to have a separate Unique Constraint.很可能您真正想要的是,基于您不希望表ShoppingCard EmailAddressUserID作为主键,并且电子邮件地址具有单独的唯一约束。 This gives you the following instead:这将为您提供以下内容:

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);

I also give your constraints explicit names, a habit you should really get into.我还为您的约束提供了明确的名称,这是您应该真正养成的习惯。

Now you can INSERT the sample data, and UPDATE the email address without issue:现在您可以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;

And if you try to add another user with the same email address, you get an error:如果您尝试添加具有相同电子邮件地址的其他用户,则会收到错误消息:

INSERT INTO dbo.[User] (EmailAddress, FirstName, LastName)
VALUES(N'Jane.Bloggs@email.com','Jane','Bloggs');

Violation of UNIQUE KEY constraint 'UQ_UserEmail'.违反 UNIQUE KEY 约束“UQ_UserEmail”。 Cannot insert duplicate key in object 'dbo.User'.无法在对象“dbo.User”中插入重复键。 The duplicate key value is (Jane.Bloggs@email.com).重复的键值为 (Jane.Bloggs@email.com)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM