Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Comment créer une clé étrangère composite dans SQL Server (exemple T-SQL)

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.