简体   繁体   中英

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 ?

在此处输入图片说明

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 ; no such constraint exists and as such the creation of the FOREIGN KEY fails.

To address this literally, you would need to add the EmailAddress column to the ShoppingCart table and the FOREIGN KEY 's definition:

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:

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".

This is because the value of EmailAddress in the table ShoppingCart is still N'Jane@bloggs.com' , so the value can't be updated. Obviously, you can't also UPDATE the value in dbo.ShopppingCart because you'll get the same error:

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".

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. 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. 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 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'. Cannot insert duplicate key in object 'dbo.User'. The duplicate key value is (Jane.Bloggs@email.com).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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