Une clé étrangère composite est une clé étrangère composée de plusieurs colonnes.
Cet article fournit un exemple de création d'une clé étrangère composite à l'aide de Transact-SQL dans SQL Server.
Vous pouvez créer une clé étrangère composite comme vous créeriez une seule clé étrangère, sauf qu'au lieu de spécifier une seule colonne, vous fournissez le nom de deux colonnes ou plus, séparées par une virgule.
Comme ceci :
CONSTRAINT FK_FKName FOREIGN KEY (FKColumn1, FKColumn2) REFERENCES PrimaryKeyTable (PKColumn1, PKColumn2)
Exemple 1 - Créer une clé étrangère composite
Voici un exemple de base de données utilisant une clé étrangère composite (et une clé primaire composite).
Pour les besoins de cet exemple, je vais créer une base de données appelée BandTest :
CREATE DATABASE BandTest;
Maintenant que la base de données est créée, allons-y et créons les tables.
USE BandTest; CREATE TABLE Musician ( MusicianId int NOT NULL, FirstName varchar(60), LastName varchar(60), CONSTRAINT PK_Musician PRIMARY KEY (MusicianID) ); CREATE TABLE Band ( BandId int NOT NULL, BandName varchar(255), CONSTRAINT PK_Band PRIMARY KEY (BandId) ); CREATE TABLE BandMember ( MusicianId int NOT NULL, BandId int NOT NULL, CONSTRAINT PK_BandMember PRIMARY KEY (MusicianID, BandId), CONSTRAINT FK_BandMember_Band FOREIGN KEY (BandId) REFERENCES Band(BandId), CONSTRAINT FK_BandMember_Musician FOREIGN KEY (MusicianId) REFERENCES Musician(MusicianId) ); CREATE TABLE MembershipPeriod ( MembershipPeriodId int NOT NULL, MusicianId int NOT NULL, BandId int NOT NULL, StartDate date NOT NULL, EndDate date NULL, CONSTRAINT PK_MembershipPeriod PRIMARY KEY (MembershipPeriodID), CONSTRAINT FK_MembershipPeriod_BandMember FOREIGN KEY (MusicianID, BandId) REFERENCES BandMember(MusicianID, BandId) );
Dans cet exemple, le BandMember
table a une clé primaire multicolonne. La MembershipPeriod
table a une clé étrangère qui fait référence à cette clé primaire multicolonne. Par conséquent, les définitions de clé primaire et étrangère incluent les colonnes séparées par une virgule.
Le raisonnement derrière la conception de la base de données ci-dessus est qu'un musicien pourrait potentiellement être membre de nombreux groupes. De plus, chaque groupe peut avoir plusieurs musiciens. Nous avons donc une relation plusieurs à plusieurs. C'est pourquoi le BandMember
table est créée – elle est utilisée comme table de concordance entre le Musician
table et la Band
table. Dans ce cas, j'ai choisi d'utiliser une clé primaire composite.
Mais un musicien peut également être membre d'un groupe à plusieurs reprises (par exemple, un musicien peut quitter un groupe, pour revenir plus tard). Par conséquent, la MembershipPeriod
tableau peut être utilisé pour enregistrer toutes les périodes où chaque musicien a été membre de chaque groupe. Cela doit référencer la clé primaire composite sur le BandMember
table, et je dois donc créer une clé étrangère multicolonne.
Exemple 2 – Insérer des données
Après avoir exécuté le code ci-dessus, je peux maintenant charger la base de données avec des données :
INSERT INTO Musician VALUES ( 1, 'Ian', 'Paice' ), ( 2, 'Roger', 'Glover' ), ( 3, 'Richie', 'Blackmore' ), ( 4, 'Rod', 'Evans' ), ( 5, 'Ozzy', 'Osbourne' ); INSERT INTO Band VALUES ( 1, 'Deep Purple' ), ( 2, 'Rainbow' ), ( 3, 'Whitesnake' ), ( 4, 'Iron Maiden' ); INSERT INTO BandMember VALUES ( 1, 1 ), ( 1, 3 ), ( 2, 1 ), ( 2, 2 ), ( 3, 1 ), ( 3, 2 ), ( 4, 1 ); INSERT INTO MembershipPeriod VALUES ( 1, 1, 1, '1968-03-01', '1976-03-15' ), ( 2, 1, 1, '1984-04-01', NULL ), ( 3, 1, 3, '1979-08-01', '1982-01-01' ), ( 4, 2, 1, '1969-01-01', '1973-06-29' ), ( 5, 2, 1, '1984-04-01', NULL ), ( 6, 2, 2, '1979-01-01', '1984-01-01' ), ( 7, 3, 1, '1968-03-01', '1975-06-21' ), ( 8, 3, 1, '1984-04-01', '1993-11-17' ), ( 9, 3, 2, '1975-02-01', '1984-04-01' ), ( 10, 3, 2, '1993-11-17', '1997-05-31' ), ( 11, 3, 2, '2015-01-01', NULL ), ( 12, 4, 1, '1968-03-01', '1969-12-01' );
Exemple 3 – Requête de base
Voici un exemple de requête pouvant être exécutée sur la base de données :
SELECT CONCAT(m.FirstName, ' ', m.LastName) AS 'Musician', b.BandName AS 'Band', mp.StartDate AS 'Start', mp.EndDate AS 'End' FROM Musician m JOIN BandMember bm ON m.MusicianId = bm.MusicianId JOIN Band b ON b.BandId = bm.BandId AND m.MusicianId = bm.MusicianId JOIN MembershipPeriod mp ON mp.BandId = b.BandId AND mp.MusicianId = m.MusicianId;
Résultat :
+------------------+-------------+------------+------------+ | Musician | Band | Start | End | |------------------+-------------+------------+------------| | Ian Paice | Deep Purple | 1968-03-01 | 1976-03-15 | | Ian Paice | Deep Purple | 1984-04-01 | NULL | | Ian Paice | Whitesnake | 1979-08-01 | 1982-01-01 | | Roger Glover | Deep Purple | 1969-01-01 | 1973-06-29 | | Roger Glover | Deep Purple | 1984-04-01 | NULL | | Roger Glover | Rainbow | 1979-01-01 | 1984-01-01 | | Richie Blackmore | Deep Purple | 1968-03-01 | 1975-06-21 | | Richie Blackmore | Deep Purple | 1984-04-01 | 1993-11-17 | | Richie Blackmore | Rainbow | 1975-02-01 | 1984-04-01 | | Richie Blackmore | Rainbow | 1993-11-17 | 1997-05-31 | | Richie Blackmore | Rainbow | 2015-01-01 | NULL | | Rod Evans | Deep Purple | 1968-03-01 | 1969-12-01 | +------------------+-------------+------------+------------+
Nous pouvons donc maintenant voir à quelles dates chaque musicien a été membre de chaque groupe, même s'il a été membre à plusieurs reprises.
Exemple 4 – Requête légèrement modifiée
Nous pourrions modifier la requête ci-dessus pour fournir les résultats dans un format légèrement plus lisible :
SELECT CONCAT(m.FirstName, ' ', m.LastName) AS 'Musician', b.BandName AS 'Band', STRING_AGG( CONCAT(FORMAT(mp.StartDate, 'yyyy'), '-', ISNULL(FORMAT(mp.EndDate, 'yyyy'), 'present')), ', ') AS 'Time with the band' FROM Musician m JOIN BandMember bm ON m.MusicianId = bm.MusicianId JOIN Band b ON b.BandId = bm.BandId AND m.MusicianId = bm.MusicianId JOIN MembershipPeriod mp ON mp.BandId = b.BandId AND mp.MusicianId = m.MusicianId GROUP BY m.FirstName, m.LastName, b.BandName;
Résultat :
+------------------+-------------+------------------------------------+ | Musician | Band | Time with the band | |------------------+-------------+------------------------------------| | Ian Paice | Deep Purple | 1968-1976, 1984-present | | Ian Paice | Whitesnake | 1979-1982 | | Richie Blackmore | Deep Purple | 1968-1975, 1984-1993 | | Richie Blackmore | Rainbow | 1975-1984, 1993-1997, 2015-present | | Rod Evans | Deep Purple | 1968-1969 | | Roger Glover | Deep Purple | 1969-1973, 1984-present | | Roger Glover | Rainbow | 1979-1984 | +------------------+-------------+------------------------------------+
Cet exemple tire parti du STRING_AGG()
fonction de concaténation des différentes périodes de temps pour chaque musicien. Cela finit par réduire le nombre de lignes nécessaires et nous permet de regrouper les périodes de temps dans le même champ.
Je profite aussi du ISNULL()
fonction, ce qui me permet de changer toutes les valeurs NULL en quelque chose de plus significatif.
Notez que ISNULL()
exige que le deuxième argument soit d'un type qui peut être implicitement converti dans le type du premier argument. Dans ce cas, le premier argument était à l'origine une date type, ce qui signifie que je ne pourrais pas utiliser de chaîne. Cependant, dans ce cas, j'ai décidé d'utiliser le FORMAT()
fonction pour formater la date valeur. Cette fonction convertit implicitement la date valeur à une chaîne, et j'ai donc pu utiliser une chaîne pour le deuxième argument.