En plus de votre clé primaire dans la table Address (sur Id), vous devez également déclarer une autre contrainte de clé, une contrainte UNIQUE, sur (Id, UserId).
ALTER TABLE Address ADD CONSTRAINT UQ_Address_UserCheck UNIQUE (Id,UserID)
Vous pouvez remplacer vos FKs existants de commande à l'adresse, ou ajouter d'autres, qui vérifient les deux colonnes
ALTER TABLE Order ADD CONSTRAINT
FK_Order_DeliveryAddress_UserCheck FOREIGN KEY (DeliveryAddressID,UserID)
references Address (Id,UserId)
Comme je le dis, vous pouvez ajouter ces tout comme des contraintes supplémentaires, si tu veux.
Alors, avec quelques légers coups secs de nommage, vos tableaux sont rendus comme ceci:
create table Users (
UserID int IDENTITY(1,1) not null,
Name varchar(30) not null,
/* Other columns */
constraint PK_Users PRIMARY KEY (UserID),
constraint UQ_User_Names UNIQUE (Name)
)
go
create table Addresses (
AddressID int IDENTITY(1,1) not null,
UserID int not null,
Street varchar(35) not null,
/* Other columns */
constraint PK_Addresses PRIMARY KEY (AddressID),
constraint FK_Addresses_Users FOREIGN KEY (UserID) references Users (UserID),
constraint UQ_Addresses_UserCheck UNIQUE (UserID,AddressID)
)
go
create table Orders (
OrderID int IDENTITY (1,1) not null,
UserID int not null,
DeliveryAddressID int not null,
BillingAddressID int not null,
/* Other columns - there may be other nullability concerns above */
constraint PK_Orders PRIMARY KEY (OrderID),
constraint FK_Orders_Users FOREIGN KEY (UserID) references Users (UserID),
constraint FK_Orders_DeliveryAddresses FOREIGN KEY (DeliveryAddressID) references Addresses (AddressID),
constraint FK_Orders_BillingAddresses FOREIGN KEY (BillingAddressID) references Addresses (AddressID),
/* Further constraints - ensure UserID -> AddressID match */
constraint FK_Orders_DeliveryAddress_UserCheck FOREIGN KEY (UserID,DeliveryAddressID) references Addresses (UserID,AddressID),
constraint FK_Orders_BillingAddress_UserCheck FOREIGN KEY (UserID,BillingAddressID) references Addresses (UserID,AddressID)
)
Et essayer notre avec des inserts qui devraient fonctionner, sauf pour le dernier (où il y a un utilisateur/décalage adresse), il fonctionne:
declare @UID1 int
declare @UID2 int
declare @AID1_1 int
declare @AID1_2 int
declare @AID2_1 int
declare @AID2_2 int
insert into Users (Name)
select 'User1'
set @UID1 = SCOPE_IDENTITY()
insert into Users (Name)
select 'User2'
set @UID2 = SCOPE_IDENTITY()
insert into Addresses (UserID,Street)
select @UID1,'Street1'
set @AID1_1 = SCOPE_IDENTITY()
insert into Addresses (UserID,Street)
select @UID1,'Street2'
set @AID1_2 = SCOPE_IDENTITY()
insert into Addresses (UserID,Street)
select @UID2,'Street1'
set @AID2_1 = SCOPE_IDENTITY()
insert into Addresses (UserID,Street)
select @UID2,'Street2'
set @AID2_2 = SCOPE_IDENTITY()
insert into Orders (UserID,DeliveryAddressID,BillingAddressID)
select @UID1,@AID1_1,@AID1_2 union all
select @UID2,@AID2_1,@AID2_1
insert into Orders (UserID,DeliveryAddressID,BillingAddressID)
select @UID1,@AID1_1,@AID2_1
Résultats:
(1 row(s) affected)
(1 row(s) affected)
(1 row(s) affected)
(1 row(s) affected)
(1 row(s) affected)
(1 row(s) affected)
(2 row(s) affected)
Msg 547, Level 16, State 0, Line 31
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Orders_BillingAddress_UserCheck". The conflict occurred in database "Test", table "dbo.Addresses".
The statement has been terminated.
Vous devez vérifier toutes les données envoyées avant de l'insérer. Vous pouvez définir un champ à insérer dans votre structure ddbb, mais vous devez toujours vérifier le serveur de données avant d'atteindre le ddbb. – Chumillas
Merci - je peux et je le ferai - mais je voudrais quand même mettre en place une vérification dans la base de données si je peux - comme la DB est en fin de compte où «l'argent s'arrête» quand il s'agit d'intégrité référentielle. – Stuart
La seule façon de vérifier cette condition dans la base de données est d'avoir un déclencheur ON INSERT dans les tables en respectant l'intégrité. [HowTo] (http://msdn.microsoft.com/fr-fr/library/ee336242.aspx) – Chumillas