Некромантування.
Правильна відповідь: це залежить від того, який двигун бази даних та який інструмент управління.
Давайте зробимо приклад: у
нас є таблиця звітів,
і у звіті може бути батьківський (пункт меню, як категорія),
а сам батьків може мати батьківського (наприклад, Центр прибутку)
тощо.
Найпростіший приклад стандартного рекурсивного відносини, як і будь-яка суть, що посилається на себе, ієрархія.
Отримана таблиця SQL-сервера:
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'dbo.FK_T_FMS_Reports_T_FMS_Reports') AND parent_object_id = OBJECT_ID(N'dbo.T_FMS_Reports'))
ALTER TABLE dbo.T_FMS_Reports DROP CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.T_FMS_Reports') AND type in (N'U'))
DROP TABLE dbo.T_FMS_Reports
GO
CREATE TABLE dbo.T_FMS_Reports
(
RE_UID uniqueidentifier NOT NULL
,RE_RE_UID uniqueidentifier NULL
,RE_Text nvarchar(255) NULL
,RE_Link nvarchar(400) NULL
,RE_Sort int NOT NULL
,RE_Status int NOT NULL
,PRIMARY KEY CLUSTERED ( RE_UID )
);
GO
ALTER TABLE dbo.T_FMS_Reports WITH CHECK ADD CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports FOREIGN KEY(RE_RE_UID)
REFERENCES dbo.T_FMS_Reports (RE_UID)
-- ON DELETE CASCADE -- here, MS-SQL has a problem
GO
ALTER TABLE dbo.T_FMS_Reports CHECK CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports
GO
Але у вас виникає проблема:
Коли вам потрібно видалити точку меню з усіма її підменю, ви не можете встановити каскад delete, оскільки Microsoft SQL-сервер не підтримує рекурсивні каскадні видалення (з іншого боку, PostGreSQL робить [але тільки якщо графік не циклічний], тоді як MySQL взагалі не любить подібну структуру таблиці, оскільки вона не підтримує рекурсивні CTE).
Таким чином, ви начебто підірвали цілісність / функціональність видалення з ним, зробивши обов'язковим впровадження такої функціональності у власному коді або у збереженій процедурі (якщо ваш RDBMS підтримує збережені процедури).
Це, без сумніву, підірве будь-який вид автоматичного імпорту / експорту динамічних даних, тому що ви не можете просто запустити операцію видалення для всіх таблиць відповідно до (несанкціонованих) зв'язків із зовнішніми ключами, а також не можете просто вибрати * і створити вставку для кожного рядка у довільному порядку.
Наприклад, коли ви створюєте скрипт INSERT за допомогою SSMS, то SSMS не отримуватиме зовнішній ключ, і, таким чином, дійсно створює вкладиші-заяви, які будуть вставляти записи з залежностями, перш ніж він вставить батьківський зв'язок залежності, який вийде з ладу з помилкою , тому що сторонній ключ є на місці.
Однак у належних системах управління базами даних (на зразок PostgreSQL), при належному інструменті це не повинно бути проблемою. Просто відмовляйтесь від того, що ви просто платите за свої RDBMS (я дивлюся на вас, Microsoft; Oracle =?) Та / або його пояс, це не означає, що він правильно запрограмований. І OpenSource (наприклад, MySQL) не змушує вас не сприйняти таких чудових дрібниць.
Диявол у деталях, як йдеться у старому вислові.
Тепер не те, що ви не могли вирішити подібні проблеми, але я дійсно не рекомендую цього, якщо ваша система буде складною (наприклад, 200+ таблиць).
Крім того, у звичайній комерційній обстановці (як зображує Ділберт) вам просто не дадуть цього часу.
Набагато кращим підходом, хоча і складніше, буде таблиця закриття.
Це було б додатковим бонусом, що він також працює на MySQL.
Після того, як ви реалізуєте функцію закриття один раз, ви змусите його працювати в додаткових місцях майже взагалі.