Contrainte SQL pour empêcher les foreign keys incompatibles

J'ai trois tables, Customer , PhoneNumber et PhoneCall .

PhoneNumber contient des numéros de téléphone et chaque numéro de téléphone appartient à un client.

PhoneCall contient un journal des appels et des references du client à qui l'appel a été fait, avec le numéro de téléphone qui a été appelé.

Je souhaite créer une contrainte qui empêche la création d'inputs dans la table PhoneCall où le PhoneNumber référencé n'appartient pas au Customer référencé.

Voici mes tables:

 Customer Id Name PhoneNumber Id CustomerId (fk to Customer.Id) AreaCode Number PhoneCall CustomerId (fk to Customer.Id) PhoneNumberId (fk to PhoneNumber.Id) Description Duration 

Exemples de clients et de numéros de téléphone:

 Customers = [ { Id: 1, Name: 'Bob' }, { Id: 2, Name: 'Richard' }, ]; PhoneNumbers = [ { Id: 1, CustomerId: 1, AreaCode: 'xxx', Number: 'xxxx' }, { Id: 2, CustomerId: 2, AreaCode: 'yyy', Number: 'yyyy' } ]; 

Je veux empêcher une input comme celle-ci:

 PhoneCall = { CustomerId: 1, PhoneNumber: 2, Description: 'call to customer', Duration: 5 } 

Cela semble être quelque chose qui devrait être facile à résoudre avec une contrainte, mais j'ai vraiment du mal à comprendre comment cela devrait être fait. Existe-t-il un type de contrainte pour résoudre ce problème?

Mettre à jour

Merci pour la réponse Kentaro.

Ce que j'aime le plus, c'est que je peux save des appels téléphoniques avec PhoneNumberId défini sur null si aucun numéro de téléphone n'a été spécifié.

Voici les requêtes que j'ai utilisées pour append la contrainte

 ALTER TABLE [PhoneNumbers] ADD UNIQUE ([Id], [CustomerId]); ALTER TABLE [dbo].[PhoneCalls] ADD CONSTRAINT [FK_dbo.PhoneCalls_dbo.ReferencedPhoneNumberMustBelongToReferencedCustomer] FOREIGN KEY([PhoneNumberId], [CustomerId]) REFERENCES [dbo].[PhoneNumbers] ([Id], [CustomerId]); 

Une contrainte de key étrangère peut facilement gérer cela (que vous avez déjà comme une balise). Tout ce que vous avez à faire est de modifier légèrement la définition de la table et la reference de la key étrangère dans la table PhoneCall afin qu'elle fasse reference à CustomerID dans la table PhoneNumber. Mais pour ce faire, vous devrez modifier légèrement la définition de table de PhoneNumber et de PhoneCall, car une key étrangère doit être soit une key primaire, soit une key candidate (c'est-à-dire unique) dans la table de reference. Ainsi, avec les définitions de tables fournies, dans TSQL, recréer ces tables ressemblerait à ceci (avec un type de données supposé).

 CREATE TABLE PhoneNumber( Id INT UNIQUE, CustomerId INT UNIQUE REFERENCES Customer(ID), AreaCode INT(3), Number INT(7), CONSTRAINT CK_PhoneID_CustID (ID, CustomerID)); CREATE TABLE PhoneCall ( CustomerId INT REFERENCES Phonenumber(CustomerID), PhoneNumberId INT REFERENCES PhoneNumber(Id), Description NVARCHAR(MAX), Duration INT); 

Je pense que la solution la plus simple à votre problème est: N'incluez pas CustomerId dans la table PhoneCall . Regardez-le à travers la table PhoneNumbers .

Avec un seul identifiant client, il n'y a aucune chance de conflit.

Une autre possibilité de créer un index unique redondant sur PhoneNumbers(CustomerId, PhoneNumber) . Utilisez ensuite cet index pour la reference de key étrangère. Il faudra que les identifiants du client correspondent.