Ein zusammengesetzter Fremdschlüssel ist ein Fremdschlüssel, der aus mehreren Spalten besteht.
Dieser Artikel enthält ein Beispiel für das Erstellen eines zusammengesetzten Fremdschlüssels mit Transact-SQL in SQL Server.
Sie können einen zusammengesetzten Fremdschlüssel genauso erstellen wie einen einzelnen Fremdschlüssel, mit der Ausnahme, dass Sie statt nur einer Spalte die Namen von zwei oder mehr Spalten angeben, getrennt durch ein Komma.
So:
CONSTRAINT FK_FKName FOREIGN KEY (FKColumn1, FKColumn2) REFERENCES PrimaryKeyTable (PKColumn1, PKColumn2)
Beispiel 1 – Erstellen Sie einen zusammengesetzten Fremdschlüssel
Hier ist ein Beispiel für eine Datenbank, die einen zusammengesetzten Fremdschlüssel (und einen zusammengesetzten Primärschlüssel) verwendet.
Für dieses Beispiel erstelle ich eine Datenbank namens BandTest :
CREATE DATABASE BandTest;
Nachdem die Datenbank nun erstellt wurde, können wir mit dem Erstellen der Tabellen fortfahren.
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) );
In diesem Beispiel das BandMember
Tabelle hat einen mehrspaltigen Primärschlüssel. Der MembershipPeriod
Tabelle hat einen Fremdschlüssel, der auf diesen mehrspaltigen Primärschlüssel verweist. Daher enthalten sowohl die Primär- als auch die Fremdschlüsseldefinition die durch ein Komma getrennten Spalten.
Der Grund für das obige Datenbankdesign ist, dass ein Musiker potenziell Mitglied vieler Bands sein könnte. Außerdem kann jede Band viele Musiker haben. Wir haben also eine Viele-zu-Viele-Beziehung. Aus diesem Grund ist BandMember
Tabelle erstellt – sie dient als Querverweistabelle zwischen dem Musician
Tabelle und das Band
Tisch. In diesem Fall habe ich mich für die Verwendung eines zusammengesetzten Primärschlüssels entschieden.
Ein Musiker kann aber auch mehr als einmal Mitglied einer Band sein (z. B. ein Musiker verlässt eine Band, um später wiederzukommen). Daher die MembershipPeriod
Tabelle kann verwendet werden, um alle Perioden aufzuzeichnen, die jeder Musiker Mitglied jeder Band war. Dies muss auf den zusammengesetzten Primärschlüssel auf BandMember
verweisen Tabelle, und so muss ich einen mehrspaltigen Fremdschlüssel erstellen.
Beispiel 2 – Daten einfügen
Nachdem ich gerade den obigen Code ausgeführt habe, kann ich jetzt die Datenbank mit Daten laden:
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' );
Beispiel 3 – Grundlegende Abfrage
Hier ist ein Beispiel für eine Abfrage, die für die Datenbank ausgeführt werden könnte:
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;
Ergebnis:
+------------------+-------------+------------+------------+ | 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 | +------------------+-------------+------------+------------+
So können wir jetzt sehen, wann jeder Musiker Mitglied jeder Band war, auch wenn er mehrfach Mitglied war.
Beispiel 4 – Leicht modifizierte Abfrage
Wir könnten die obige Abfrage ändern, um die Ergebnisse in einem etwas besser lesbaren Format bereitzustellen:
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;
Ergebnis:
+------------------+-------------+------------------------------------+ | 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 | +------------------+-------------+------------------------------------+
Dieses Beispiel nutzt STRING_AGG()
Funktion, um die verschiedenen Zeiträume für jeden Musiker zu verketten. Dies reduziert die Anzahl der erforderlichen Zeilen und ermöglicht es uns, die Zeiträume im selben Feld zusammenzufassen.
Ich nutze auch ISNULL()
-Funktion, mit der ich alle NULL-Werte in etwas Sinnvolleres ändern kann.
Beachten Sie, dass ISNULL()
erfordert, dass das zweite Argument einen Typ hat, der implizit in den Typ des ersten Arguments konvertiert werden kann. In diesem Fall war das erste Argument ursprünglich ein Datum type, was bedeutet, dass ich keine Zeichenfolge verwenden könnte. Allerdings habe ich mich in diesem Fall für das FORMAT()
entschieden Funktion zum Formatieren des Datums Wert. Diese Funktion konvertiert implizit das Datum value in einen String, und daher konnte ich einen String für das zweite Argument verwenden.