složený cizí klíč je cizí klíč skládající se z více sloupců.
Tento článek poskytuje příklad vytvoření složeného cizího klíče pomocí Transact-SQL v SQL Server.
Složený cizí klíč můžete vytvořit stejně, jako byste vytvořili jeden cizí klíč, s tím rozdílem, že místo určení pouze jednoho sloupce zadáte název dvou nebo více sloupců oddělených čárkou.
Takhle:
CONSTRAINT FK_FKName CIZÍ KLÍČ (FKColumn1, FKColumn2)REFERENCE PrimaryKeyTable (PKColumn1, PKColumn2)
Příklad 1 – Vytvoření složeného cizího klíče
Zde je příklad databáze používající složený cizí klíč (a složený primární klíč).
Pro účely tohoto příkladu vytvořím databázi s názvem BandTest :
CREATE DATABASE BandTest;
Nyní, když je databáze vytvořena, pojďme do toho a vytvořte tabulky.
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) ,CONSTRAINT PK_Band PRIMARY KEY (BandId));CREATE TABLE Člen kapely (MusicianId int NOT NULL,BandId int NOT NULL,CONSTRAINT PK_BandMember PRIMÁRNÍ KLÍČ (MusicianID, BandId),CONSTRAINT FK_BandId KEY (dBandM BandId KEY) a CONSTRAINT FK_BandEIGN KEY_andM FORFERENCEGNULL_andM BandI. KEY (MusicianId) REFERENCE Musician(MusicianId));VYTVOŘIT TABULKU MembershipPeriod (MembershipPeriodId int NOT NULL,MusicianId int NOT NULL,BandId int NOT NULL,StartDatum NOT NULL,EndDate PRIINTRYPEKMKEYMeriod KEY (MusicianID, BandId) REFERENCE BandMember(MusicianID, BandId));
V tomto příkladu BandMember
tabulka má vícesloupcový primární klíč. MembershipPeriod
tabulka má cizí klíč, který odkazuje na tento vícesloupcový primární klíč. Proto definice primárního i cizího klíče zahrnují sloupce oddělené čárkou.
Důvodem výše uvedeného návrhu databáze je, že hudebník by mohl být potenciálně členem mnoha kapel. Každá kapela může mít také mnoho hudebníků. Takže máme vztah mnoho k mnoha. To je důvod, proč BandMember
je vytvořena tabulka – používá se jako křížová referenční tabulka mezi Musician
tabulka a Band
stůl. V tomto případě jsem se rozhodl použít složený primární klíč.
Ale hudebník může být také členem skupiny při více než jedné příležitosti (např. hudebník může kapelu opustit, aby se později vrátil). Proto MembershipPeriod
tabulku lze použít k zaznamenání všech období, kdy byl každý hudebník členem každé kapely. To musí odkazovat na složený primární klíč na BandMember
tabulky, a proto musím vytvořit vícesloupcový cizí klíč.
Příklad 2 – Vložení dat
Po spuštění výše uvedeného kódu nyní mohu načíst databázi s daty:
INSERT INTO MusicianVALUES ( 1, 'Ian', 'Paice' ),( 2, 'Roger', 'Glover' ),( 3, 'Richie', 'Blackmore' ),( 4, 'Rod', ' Evans' ),( 5, 'Ozzy', 'Osbourne' );INSERT INTO BandVALUES ( 1, 'Deep Purple' ),( 2, 'Rainbow' ),( 3, 'Whitesnake' ),( 4, 'Iron Maiden ' );INSERT INTO BandMemberVALUES ( 1, 1 ),( 1, 3 ),( 2, 1 ),( 2, 2 ),( 3, 1 ),( 3, 2 ),( 4, 1 );INSERT INTO MembershipPeriodVALUES ( 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');
Příklad 3 – Základní dotaz
Zde je příklad dotazu, který lze spustit proti databázi:
SELECT CONCAT(m.FirstName, ' ', m.LastName) AS 'Musician', b.BandName AS 'Band', mp.StartDate AS 'Start', mp.EndDate AS 'End'FROM Musician mJOIN BandMember bm ON m.MusicianId =bm.MusicianIdJOIN Kapela b ON b.BandId =bm.BandId AND m.MusicianId =bm.MusicianIdJOIN Členství Období mpON mp.BandId =b.BandId AND mp.MusicianId =>Výsledek:
+------------------+-------------+------------+ ------------+| Hudebník | Kapela | Start | Konec ||------------------+-------------+------------+- -----------|| 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 | Duha | 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 | Duha | 1975-02-01 | 1984-04-01 || Richie Blackmore | Duha | 1993-11-17 | 1997-05-31 || Richie Blackmore | Duha | 2015-01-01 | NULL || Rod Evans | Deep Purple | 1968-03-01 | 1969-12-01 |+------------------+--------------+----------- --+------------+Nyní tedy můžeme vidět, kdy byl každý hudebník členem každé kapely, i když byl členem vícekrát.
Příklad 4 – Mírně upravený dotaz
Výše uvedený dotaz bychom mohli upravit tak, aby poskytoval výsledky v trochu čitelnějším formátu:
SELECT CONCAT(m.FirstName, ' ', m.LastName) AS 'Muzikant', b.BandName AS 'Kapela', STRING_AGG( CONCAT(FORMAT(mp.StartDate, 'yyyy'), '-', ISNULL (FORMAT(mp.EndDate, 'yyyy'), 'současnost')), ', ') AS 'Čas s kapelou'FROM Musician mJOIN BandMember bm ON m.MusicianId =bm.MusicianIdJOIN Band b ON b.BandId =bm .BandId AND m.MusicianId =bm.MusicianIdJOIN MembershipPeriod mpON mp.BandId =b.BandId AND mp.MusicianId =m.MusicianIdGROUP BY m.FirstName, m.LastName, b.BandName;Výsledek:
+------------------+-------------+------------- ------------------------+| Hudebník | Kapela | Čas s kapelou ||------------------+-------------+------------ -------------------------|| Ian Paice | Deep Purple | 1968-1976, 1984-dosud || Ian Paice | Whitesnake | 1979-1982 || Richie Blackmore | Deep Purple | 1968-1975, 1984-1993 || Richie Blackmore | Duha | 1975-1984, 1993-1997, 2015-dosud || Rod Evans | Deep Purple | 1968-1969 || Roger Glover | Deep Purple | 1969-1973, 1984-dosud || Roger Glover | Duha | 1979-1984 |+------------------+-------------+------------- ------------------------+Tento příklad využívá
STRING_AGG()
funkce pro zřetězení různých časových období pro každého hudebníka. Tím se sníží počet požadovaných řádků a umožní nám seskupit časová období ve stejném poli.Také využívám výhody
ISNULL()
funkce, která mi umožňuje změnit jakékoli hodnoty NULL na něco smysluplnějšího.Všimněte si, že
ISNULL()
vyžaduje, aby druhý argument byl typu, který lze implicitně převést na typ prvního argumentu. V tomto případě bylo prvním argumentem původně datum typ, což znamená, že bych nemohl použít řetězec. V tomto případě jsem se však rozhodl použítFORMAT()
funkce pro formátování data hodnota. Tato funkce implicitně převádí datum hodnotu na řetězec, a proto jsem mohl použít řetězec pro druhý argument.