Новак? Тогава външният ключ на SQL може да ви е чужд.
Може да сте чували различни мнения за външните ключове на SQL. Ако не сте, скоро ще го направите. Или вашият опит ще повлияе на вашето виждане. Основното нещо, което трябва да знаете, е, че външните ключове са задължителни в релационните бази данни.
Въпреки това, някои разработчици могат да премахнат или игнорират външни ключове, когато са изправени пред някои усложнения. И така, какво да правя? Да използвате външния ключ или да не го използвате? Ще има ли моменти, когато няма да е необходимо да ги използвате?
Това ръководство е за да видите колко важно е това нещо. Освен това ще знаете някои грешки в кода и ще научите как да ги коригирате. Освен това, разбира се, ще използваме практически примери. Няма нищо, с което да не можете да се справите.
Какво е SQL външен ключ?
Първо най-важното. Какво е външният ключ в SQL? С няколко думи, това е ключ, който свързва 2 таблици. Да приемем, че имате родителска и дъщерна маса. Има някаква обща черта, която ги прави родител и дете – ключът, който свързва тези 2 таблици.
Въпреки това, в SQL бази данни външният ключ не се отнася само до таблици. Той налага връзката. Ето защо се нарича ограничение за външен ключ.
Ще възникне грешка, ако се опитате да добавите дъщерен запис със стойност на външен ключ, който не съществува в първичните ключове на родителската таблица. По-късно ще видим примерни кодове, които илюстрират това.
Кои таблици трябва да имат ограничения на външния ключ на SQL?
Дъщерните таблици могат да имат външни ключове. Един външен ключ може да препраща към друга таблица. Също така, може да има няколко външни ключа в „детска“ таблица. В SQL Server външният ключ може да препраща към първичен ключ или уникален ключ в друга таблица.
Какво ще кажете за Self-Reference?
Това излиза от общата дефиниция за външен ключ. Асобствена справка означава, че можете да зададете външен ключ, който препраща различна колона в същата таблица . SQL Server, MySQL и Oracle поддържат това.
Самореференцията е приложима, когато искате да създадете йерархии като връзката между мениджър и персонал. Разрешено е, но повечето реализации на външни ключове са между 2 таблици.
По-късно ще имаме примери.
4 предимства от използването на външни ключове на SQL
Нека разгледаме подробно първичния и външния ключ в SQL. Какво прави външните ключове задължителни за SQL база данни? Нека разгледаме 4 точки (тук синтаксисът на ограничението няма да има значение).
1. Избягвайте „липсващи“ данни
„Липсващи“ данни са стойности на външни ключове от дъщерни таблици без свързани стойности на първичен ключ от родителската таблица. Те също се наричат осиротели редове. Когато това се случи, можем да кажем, че базата данни има малка или никаква референтна цялост.
С наложени ограничения за външния ключ, „липсващите“ данни изобщо няма да се случат. Двигателят на базата данни няма да позволи изтриване на стойност на първичен ключ, която е посочена от друга таблица. По същия начин, вмъкването на външен ключ в дъщерната таблица, който не съществува в първичните ключове на родителската таблица, ще предизвика грешка.
Какво е най-лошото нещо, което може да се случи, ако не използвате ограниченията на външния ключ? Ето няколко:
- Клиентите няма да получават продукти, за които са платили.
- Лечение не се прилага на пациенти.
- Липсващите контролни списъци пропускат предпазните мерки.
Можете да обработвате тези неща извън базата данни, но трябва да ги кодирате. Повече за това ще последват.
Да кажем, че разработчик във вашата организация се справи със същото ограничение извън базата данни. Ще бъде ли отговорен и ще отстрани ли проблема в производството, ако кодът се провали? не мисля така. А ако сте администратор на базата данни? След това ще трябва да почистите бъркотията им. Не е толкова обнадеждаващо, ако питате мен.
2. Избягвайте непоследователни отчети
Отнася се до първата точка. Ако някои данни „липсват“, в различни отчети се появяват непоследователни суми. Подробностите не съвпадат с обобщенията. Осиротените редове се добавят към общите суми на обобщенията. Междувременно подробният отчет не улови оставени редове поради вътрешно присъединяване към родителските таблици.
Ако вашата работа е да поддържате базата си данни в добро състояние, вие също ще почистите тази бъркотия.
3. Не е необходим код, за да се избегнат осиротяващи редове
Ограниченията на външния ключ действат като самопочистващи се агенти. Вместо вие да почиствате бъркотията, базата данни го прави, като не позволява осиротели редове. Ограниченията на външния ключ също действат като полиция. Те арестуват погрешната логика, която причинява осиротели редове, третирайки я като престъпление, извършено извън базата данни.
Искате ли лъскава база данни без осиротели редове? Разбира се, че го правиш. Ако искате да анализирате данните някой ден, ще се радвате, че сте използвали външни ключове. Тази база данни ще бъде добър източник за копиране на необходимите данни във вашата стационарна зона.
4. Бързо разбиране на връзките на таблицата в диаграма
SQL Server Management Studio има вграден инструмент за диаграмиране за вашата база данни. Първичните и външните ключове правят диаграмата на базата данни информативна с един поглед. Все пак ще зависи от това колко таблици с релации сте включили в диаграмата.
Диаграмите помагат на новите членове на екипа да разберат структурата на данните. За старши съотборници може да бъде полезен и като документация.
Когато външният ключ на SQL може да бъде „проблем“ (плюс корекцията)
За да мигрирате стари данни към нова база данни, ще вмъкнете записи насипно. Ако изходната база данни има ниска референтна цялост, ще бъде трудно да се вмъкнат записи от източника. Причината е, че тук и там изскачат грешки във външния ключ.
Има ли поправка? Имате 2 опции.
- Уверете се, че първо сте попълнили референтните таблици или родителските таблици. След това попълнете дъщерните таблици. Едно усложнение е много бавно. В други случаи възникват повече грешки при ограничаване на външния ключ. Ако се случи последният случай, трябва да преоцените последователността от вмъквания и да се уверите, че първичните ключове са вмъкнати първи. Ако има проблем с „бавна работа“, помислете за следващата опция.
- Деактивирайте временно външните ключове и ги активирайте, след като миграцията приключи (и почисти). Можете да го направите в SQL Server Management Studio или да използвате T-SQL ALTER TABLE. Въпреки това е по-лесно да се каже, отколкото да се направи. В този момент се нуждаете от повече търпение в допълнение към вашия ум и сила на волята. По-късно ще намерим синтаксиса за деактивиране и повторно активиране на външни ключове.
Друго нещо, което трябва да вземете предвид, е използването на база данни като етапна зона за OLAP или анализ на данни. Да предположим, че изходната транзакционна база данни е чиста от осиротели редове. Или можете да успеете да избегнете тези редове чрез код. След това можете да изберете да не използвате външни ключове. Външните ключове ще забавят груповите вмъквания и актуализации, особено при огромни набори от данни.
3 лесни начина за добавяне, редактиране и изтриване на ограничения на външния ключ на SQL
Какво е необходимо за добавяне, редактиране или изтриване на външни ключове? Лесно е с тези 3 съвета.
Първите две стъпки използват графичен потребителски интерфейс. Инструменти като SQL Server Management Studio или dbForge Studio за SQL Server са много добри кандидати. Третият ще използва T-SQL код. Изборът на GUI или T-SQL код зависи от ситуацията.
1. Използване на Table Designer за добавяне, редактиране и изтриване на ограничение на външния ключ на SQL
Възможно е в SQL да добавяте ограничения за външни ключове, когато създавате или променяте структура на таблица с помощта на Table Designer в SSMS. Фигура 1 по-долу показва как да получите достъп до него от главното меню, когато структурата на таблицата е отворена.
Друга възможност е да щракнете с десния бутон където и да е от дизайнера на таблицата и да изберете Връзки от контекстното меню:
След като изберете Връзки , Връзки с чуждестранни ключове ще се появи прозорец:
ВВръзки с чуждестранни ключове прозорец, можете да изберете да добавите нов външен ключ или да редактирате/изтриете съществуващ.
Ако решите да добавите или редактирате, щракнете, за да разгънете Таблиците и колоните Спецификации. След това щракнете върху елипса бутон, за да дефинирате или редактирате таблиците с първични и външни ключове.
Оттам можете да посочите колоните за първичен и външен ключ.
След като дефинирате първичния и външния ключ, щракнете върху OK . След това се върнете към дизайнера на таблицата и запазете промените.
2. Използване на диаграма на базата данни за добавяне, редактиране и изтриване на ограничение на външния ключ на SQL
Можете да използвате диаграмата на базата данни, за да създадете ограничения на външния ключ на SQL. Фигура 5 показва как да създадете връзка между две таблици, като щракнете върху таблицата с външни ключове и я плъзнете към таблицата с първичен ключ.
Когато пуснете мишката, Таблиците и колоните ще се появи прозорец като този на фигура 4. След това можете да посочите колоните за първичен и външен ключ. След това щракнете върху OK.
За да редактирате съществуваща връзка, щракнете с десния бутон върху връзка в диаграмата. След това изберете Свойства :
След това в Свойства прозорец, разгънете Таблици и колони и щракнете върху елипса бутон:
След като щракнете върху елипса бутон, Таблици и колони ще се появи прозорец. Можете да промените колоните за първичен и външен ключ (вижте Фигура 4 по-горе отново).
Междувременно, изтриване на връзка изисква щракване с десния бутон върхусъществуващ връзка. Изберете Изтриване на връзки от базата данни и щракнете върху Да когато бъдете подканени.
3. Използване на T-SQL за добавяне, редактиране и изтриване на ограничение на външния ключ на SQL
Третият начин за добавяне на външен ключ е чрез T-SQL кода. Можете да използвате SQL CREATE TABLE и да добавите ограничението за външен ключ. Или можете също да използвате ALTER TABLE, за да добавите това ограничение след създаването на таблицата.
Ето синтаксиса за използване на CREATE TABLE:
-- Single-column foreign key
CREATE TABLE Table2
(ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
col1 INT NULL REFERENCES Table1(col1)
)
GO
След като дефинирате името и типа на колоната, можете да добавите СПРАВКИ към таблица и колона. Синтаксисът по-горе показва Таблица1 таблица на col1 колона. Имайте предвид, че имената на колоните и в двете таблици трябва да са еднакви, за да са валидни за външни ключове.
Горният синтаксис е за външни ключове с една колона. Ако имате нужда от няколко колони като външни ключове, използвайте клаузата FOREIGN KEY, както следва:
-- Multiple-column foreign key
CREATE TABLE Table2
(ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 VARCHAR(10) NULL
CONSTRAINT FK_Table1_Table2 FOREIGN KEY(col1, col2)
REFERENCES Table1(col1,col2)
)
GO
След като създадете таблицата, можете да добавите външни ключове с помощта на ALTER TABLE. Ето синтаксиса:
ALTER TABLE Table2 WITH CHECK ADD CONSTRAINT FK_Table1_Table2_2 FOREIGN KEY(col3)
REFERENCES Table3(col1)
GO
За да изтриете ограничение за външен ключ, можете да използвате ALTER TABLE с DROP CONSTRAINT:
ALTER TABLE Table2
DROP CONSTRAINT FK_Table1_Table2_2
GO
Сега можем да обобщим 3 начина за добавяне, редактиране и изтриване на външни ключове:
Примери за ограничения на външния ключ в SQL (MySQL)
Дъщерна таблица с 1 препратка към родителска таблица
-- Single Reference
CREATE TABLE [dbo].[Countries](
[CountryID] [int] IDENTITY(1,1) NOT NULL,
[Country] [nvarchar](50) NOT NULL,
[ContinentID] [int] NULL,
[Modified] [datetime] NOT NULL,
CONSTRAINT [PK_Country] PRIMARY KEY CLUSTERED
(
[CountryID] ASC
))
GO
ALTER TABLE [dbo].[Countries] WITH CHECK ADD CONSTRAINT [FK_Countries_Continent] FOREIGN KEY([ContinentID])
REFERENCES [dbo].[Continent] ([ContinentID])
GO
ALTER TABLE [dbo].[Countries] CHECK CONSTRAINT [FK_Countries_Continent]
GO
За да визуализирате тази връзка, погледнете фигура 9 по-долу:
ContinentID е ключът, който свързва двете таблици заедно.
Дъщерна таблица с множество препратки
SportsCar таблицата има множество препратки към три различни таблици:
-- Multiple References
CREATE TABLE [dbo].[SportsCars](
[SportsCarID] [int] IDENTITY(1,1) NOT NULL,
[ManufacturerID] [int] NULL,
[StyleID] [int] NULL,
[CountryID] [int] NULL,
[Model] [nvarchar](50) NOT NULL,
[Years] [varchar](50) NOT NULL,
[Notes] [varchar](255) NOT NULL,
[Modified] [datetime] NOT NULL,
CONSTRAINT [PK_SportsCars] PRIMARY KEY CLUSTERED
(
[SportsCarID] ASC
))
GO
ALTER TABLE [dbo].[SportsCars] WITH CHECK ADD CONSTRAINT [FK_SportsCars_Country] FOREIGN KEY([CountryID])
REFERENCES [dbo].[Countries] ([CountryID])
GO
ALTER TABLE [dbo].[SportsCars] CHECK CONSTRAINT [FK_SportsCars_Country]
GO
ALTER TABLE [dbo].[SportsCars] WITH CHECK ADD CONSTRAINT [FK_SportsCars_Manufacturer] FOREIGN KEY([ManufacturerID])
REFERENCES [dbo].[Manufacturers] ([ManufacturerID])
GO
ALTER TABLE [dbo].[SportsCars] CHECK CONSTRAINT [FK_SportsCars_Manufacturer]
GO
ALTER TABLE [dbo].[SportsCars] WITH CHECK ADD CONSTRAINT [FK_SportsCars_Styles] FOREIGN KEY([StyleID])
REFERENCES [dbo].[Styles] ([StyleID])
GO
ALTER TABLE [dbo].[SportsCars] CHECK CONSTRAINT [FK_SportsCars_Styles]
GO
Ето как изглежда в диаграма на база данни:
Самореференция
Йерархиите на позициите показват самореференция в следната таблица:
CREATE TABLE [dbo].[Ranks](
[RankId] [int] IDENTITY(1,1) NOT NULL,
[Rank] [varchar](50) NOT NULL,
[RankLevel] [smallint] NOT NULL,
[RankParentId] [int] NULL,
CONSTRAINT [PK_Ranks] PRIMARY KEY CLUSTERED
(
[RankId] ASC
)) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Ranks] WITH CHECK ADD CONSTRAINT [FK_Ranks_Ranks] FOREIGN KEY([RankParentId])
REFERENCES [dbo].[Ranks] ([RankId])
GO
ALTER TABLE [dbo].[Ranks] CHECK CONSTRAINT [FK_Ranks_Ranks]
GO
Диаграмата на тази самореференция е проста. Линията сочи към същата таблица в самореференция.
С АКТУАЛИЗИРАНЕ и ПРИ ИЗТРИВАНЕ
С ON UPDATE CASCADE, актуализирането на стойността на колоната с първичен ключ ще актуализира и стойностите на външния ключ в свързани таблици. Междувременно, когато използвате ON DELETE CASCADE, изтриването на първичен ключ ще изтрие и външни ключове. По подразбиране за ПРИ АКТУАЛИЗИРАНЕ и ПРИ ИЗТРИВАНЕ е НЯМА ДЕЙСТВИЕ.
Ето пример за АКТУАЛИЗИРАНЕ и ИЗТРИВАНЕ КАСКАДА:
ALTER TABLE [dbo].[Countries] WITH CHECK ADD CONSTRAINT [FK_Countries_Continent] FOREIGN KEY([ContinentID])
REFERENCES [dbo].[Continent] ([ContinentID])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[SportsCars] NOCHECK CONSTRAINT [FK_SportsCars_Country]
GO
Това не е по подразбиране и не се препоръчва. Но за да ускорите груповите вмъквания и актуализации, можете временно да деактивирате външния ключ като този по-горе. След като приключите, трябва да го превключите обратно, като използвате ПРОВЕРКА НА ОГРАНИЧЕНИЕТО.
ALTER TABLE [dbo].[SportsCars] CHECK CONSTRAINT [FK_SportsCars_Country]
GO
Няма проблеми и поправки
Този раздел ще ви покаже какво се случва, когато ВМЕСНАТЕ, АКТУАЛИЗИРАТЕ или ИЗтривате записи с външни ключове. Това също предполага, че външните ключове не са деактивирани с NOCHECK ОГРАНИЧЕНИЕ. Това ще ви помогне, когато срещнете тези често срещани проблеми.
На INSERT
-- This will cause an error because countryID = 47 does not exist in the Countries table
INSERT INTO SportsCars
(ManufacturerID, StyleID, CountryID, Model, Years, Notes)
VALUES (108, 10, 47, 'F2', '2021', 'Limited Edition')
GO
Ето съобщението за грешка:
Msg 547, Level 16, State 0, Line 56
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_SportsCars_Country". The conflict occurred in database "Vehicles", table "dbo.Countries", column 'CountryID'.
The statement has been terminated.
Поправката :Добавете CountryID =47 в Държавите първо маса. След това изпълнете отново оператора INSERT по-горе. Последователността започва с вмъкване на записи в родителската таблица и след това в дъщерната таблица.
На АКТУАЛИЗИРАНЕ
-- Update CountryID to 47 will trigger an error.
UPDATE SportsCars
SET CountryID = 47
WHERE ManufacturerID = 108
GO
Ето грешката при АКТУАЛИЗИРАНЕ:
Msg 547, Level 16, State 0, Line 60
The UPDATE statement conflicted with the FOREIGN KEY constraint "FK_SportsCars_Country". The conflict occurred in database "Vehicles", table "dbo.Countries", column 'CountryID'.
The statement has been terminated.
Поправката :Добавете CountryID =47 в Държавите маса. След това изпълнете отново оператора UPDATE.
На DELETE
-- This will trigger an error because ManufacturerID = 108 is referenced in the SportsCars table
DELETE FROM Manufacturers
WHERE ManufacturerID = 108
Този код ще задейства грешката, както следва:
Msg 547, Level 16, State 0, Line 64
The DELETE statement conflicted with the REFERENCE constraint "FK_SportsCars_Manufacturer". The conflict occurred in database "Vehicles", table "dbo.SportsCars", column 'ManufacturerID'.
The statement has been terminated.
Поправката :Изтрийте съответните записи от SportsCars таблица с ИД на производител =108. След това изпълнете отново оператора DELETE по-горе. Друг начин е да активирате ON DELETE CASCADE, ако е приложимо. Последователността започва с изтриване на записи от дъщерните таблици и след това – от родителската таблица.
Вземане за вкъщи
И така, външните ключове все още ли са ви чужди?
Нека направим обобщение на това, което научихме досега.
- Външните ключове свързват две таблици (или една таблица, когато се използва самореференция). Нуждаете се от тях, за да осигурите референтната цялост.
- Можете да използвате или GUI инструмент, или T-SQL, за да добавите, редактирате или изтриете ограниченията на външния ключ.
- За GUI инструменти можете да използвате SQL Server Management Studio или dbForge Studio за SQL Server. И двете предлагат диаграми на бази данни и дизайнери на таблици за създаване на таблици с първични и външни ключове.
- CREATE TABLE и ALTER TABLE са подходящи за добавяне и изтриване на ограниченията на външния ключ.
- Можете временно да деактивирате външни ключове с NOCHECK CONSTRAINT в ALTER TABLE. Това ще ускори груповите вмъквания и актуализации. Но не забравяйте да го активирате обратно с CHECK CONSTRAINT.
- За да избегнете проблеми с външни ключове, не забравяйте да следвате правилната последователност. За INSERT и UPDATE вмъкнете първо в родителската таблица, след това в дъщерните таблици. За DELETE първо изтрийте дъщерните записи, след това изтрийте родителските записи.
Искате ли да добавите нещо, което да помогне на начинаещите да овладеят външни ключове? Коментари секцията е отворена за вашите ярки идеи. Ако ви харесва тази публикация, моля, споделете я в любимите си социални медийни платформи.