Съставен външен ключ е външен ключ, състоящ се от множество колони.
Тази статия предоставя пример за създаване на композитен външен ключ с помощта на Transact-SQL в SQL Server.
Можете да създадете съставен външен ключ точно както бихте създали единичен външен ключ, с изключение на това, че вместо да посочите само една колона, вие предоставяте имената на две или повече колони, разделени със запетая.
Като това:
ОГРАНИЧЕНИЕ FK_FKName ВЪНШЕН КЛЮЧ (FKColumn1, FKColumn2)РЕФЕРЕНЦИИ PrimaryKeyTable (PKColumn1, PKColumn2)
Пример 1 – Създаване на композитен външен ключ
Ето пример за база данни, използваща съставен външен ключ (и съставен първичен ключ).
За целите на този пример ще създам база данни, наречена BandTest :
СЪЗДАВАНЕ НА БАЗА ДАННИ BandTest;
След като базата данни е създадена, нека да продължим и да създадем таблиците.
ИЗПОЛЗВАЙТЕ BandTest;СЪЗДАЙТЕ ТАБЛИЦА Музикант (MusicianId int NOT NULL,FirstName varchar(60),LastName varchar(60),CONSTRAINT PK_Musician PRIMARY KEY (MusicianID));CREATE TABLE Band (BandId intB2andName5 NULL) ,CONSTRAINT PK_Band PRIMARY KEY (BandId));CREATE TABLE BandMember (MusicianId int NOT NULL,BandId int NOT NULL,CONSTRAINT PK_BandMember ПРАВИЛЕН КЛЮЧ (MusicianID, BandId),CONSTRAINT FK_BandMember,CONSTRAINT FK_BandMember, CONSTRAINT FK_BandMember, CONSTRAINT FK_BandMember, REGNUM FK_BandBEIGNES и BANDBFEIGNES и BANDBEIGNES и BANDBMEmber_и Ключови (MusicianiD) Референции Музикант (музикан КЛЮЧ (MusicianID, BandId) РЕФЕРЕНЦИИ BandMember(MusicianID, BandId));
В този пример BandMember
таблицата има първичен ключ от няколко колони. MembershipPeriod
таблицата има външен ключ, който препраща към този многоколонен първичен ключ. Следователно дефинициите както на първичния, така и на външния ключ включват колоните, разделени със запетая.
Причината зад горния дизайн на база данни е, че един музикант потенциално може да бъде член на много групи. Освен това всяка група може да има много музиканти. Така че имаме връзка много към много. Ето защо BandMember
таблицата е създадена – тя се използва като таблица за кръстосани препратки между Musician
таблица и Band
маса. В този случай избрах да използвам съставен първичен ключ.
Но музикантът може също да бъде член на група повече от един път (например музикант може да напусне група, само за да се върне по-късно). Следователно MembershipPeriod
таблицата може да се използва за записване на всички периоди, през които всеки музикант е бил член на всяка група. Това трябва да препраща към съставния първичен ключ на BandMember
таблица и затова трябва да създам многоколонен външен ключ.
Пример 2 – Вмъкване на данни
След като изпълних горния код, вече мога да заредя базата данни с данни:
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' );
Пример 3 – Основна заявка
Ето пример за заявка, която може да се изпълни към базата данни:
ИЗБЕРЕТЕ CONCAT(m.FirstName, ' ', m.Lastname) КАТО 'Музикант', b.BandName КАТО 'Band', mp.StartDate КАТО 'Start', mp.EndDate КАТО 'End'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.MusicianM.Резултат:
+------------------+------------+-----------+ ------------+| Музикант | Банда | Старт | Край ||-----------------+------------+-----------+- -----------|| Иън Пейс | Deep Purple | 1968-03-01 | 15.03.1976 || Иън Пейс | Deep Purple | 1984-04-01 | NULL || Иън Пейс | Бяла змия | 1979-08-01 | 1982-01-01 || Роджър Глоувър | Deep Purple | 1969-01-01 | 29.06.1973 || Роджър Глоувър | Deep Purple | 1984-04-01 | NULL || Роджър Глоувър | Дъга | 1979-01-01 | 1984-01-01 || Ричи Блекмор | Deep Purple | 1968-03-01 | 1975-06-21 || Ричи Блекмор | Deep Purple | 1984-04-01 | 17.11.1993 г. || Ричи Блекмор | Дъга | 1975-02-01 | 1984-04-01 || Ричи Блекмор | Дъга | 17.11.1993 г. | 1997-05-31 || Ричи Блекмор | Дъга | 2015-01-01 | NULL || Род Евънс | Deep Purple | 1968-03-01 | 1969-12-01 |+-----------------+------------+---------- --+-----------+Така че вече можем да видим на кои дати всеки музикант е бил член на всяка група, дори ако е бил член няколко пъти.
Пример 4 – Леко модифицирана заявка
Бихме могли да модифицираме горната заявка, за да предоставим резултатите в малко по-четлив формат:
ИЗБЕРЕТЕ CONCAT(m.FirstName, ' ', m.Lastname) КАТО 'Музикант', b.BandName КАТО 'Band', STRING_AGG( CONCAT(MP.StartDate, 'yyyy'), '-', ISNULL (FORMAT(mp.EndDate, 'yyyy'), 'prisent')), ', ') КАТО 'Време с групата'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;Резултат:
+------------------+------------+------------ -----------------------+| Музикант | Банда | Време с групата ||-----------------+------------+----------- -------------------------|| Иън Пейс | Deep Purple | 1968-1976, 1984-до момента || Иън Пейс | Бяла змия | 1979-1982 || Ричи Блекмор | Deep Purple | 1968-1975, 1984-1993 || Ричи Блекмор | Дъга | 1975-1984, 1993-1997, 2015-до момента || Род Евънс | Deep Purple | 1968-1969 || Роджър Глоувър | Deep Purple | 1969-1973, 1984-до момента || Роджър Глоувър | Дъга | 1979-1984 |+-----------------+------------+------------ ------------------------+Този пример се възползва от
STRING_AGG()
функция за свързване на различните периоди от време за всеки музикант. Това в крайна сметка намалява броя на необходимите редове и ни позволява да групираме периодите от време заедно в едно и също поле.Също така се възползвам от
ISNULL()
функция, която ми позволява да променя всички стойности NULL в нещо по-смислено.Обърнете внимание, че
ISNULL()
изисква вторият аргумент да е от тип, който може да бъде имплицитно преобразуван към типа на първия аргумент. В този случай първият аргумент първоначално беше дата type, което означава, че няма да мога да използвам низ. В този случай обаче реших да използвамFORMAT()
функция за форматиране на дата стойност. Тази функция имплицитно преобразува дата стойност към низ и затова успях да използвам низ за втория аргумент.