SQL
Каскадное удаление
Поиск…
УДАЛИТЬ КАСКАД
Предположим, у вас есть приложение, которое администрирует комнаты.
Предположим также, что ваше приложение работает на основе клиента (арендатора).
У вас несколько клиентов.
Таким образом, ваша база данных будет содержать одну таблицу для клиентов и одну для комнат.
Теперь у каждого клиента есть N номеров.
Это должно означать, что у вас есть внешний ключ на вашем столе комнаты, ссылаясь на таблицу клиентов.
ALTER TABLE dbo.T_Room WITH CHECK ADD CONSTRAINT FK_T_Room_T_Client FOREIGN KEY(RM_CLI_ID)
REFERENCES dbo.T_Client (CLI_ID)
GO
Предполагая, что клиент переходит к другому программному обеспечению, вам придется удалить его данные в своем программном обеспечении. Но если вы это сделаете
DELETE FROM T_Client WHERE CLI_ID = x
Затем вы получите нарушение внешнего ключа, потому что вы не можете удалить клиента, когда у него все еще есть комнаты.
Теперь вы должны написать код в своем приложении, который удаляет комнаты клиента до того, как он удалит клиента. Предположим далее, что в будущем в вашей базе данных будет добавлено гораздо больше зависимостей от внешнего ключа, поскольку функциональность вашего приложения расширяется. Какой ужас. Для каждой модификации в вашей базе данных вам придется адаптировать код приложения в N местах. Возможно, вам придется адаптировать код и в других приложениях (например, интерфейсы к другим системам).
Есть лучшее решение, чем делать это в вашем коде.
Вы можете просто добавить ON DELETE CASCADE
к вашему внешнему ключу.
ALTER TABLE dbo.T_Room -- WITH CHECK -- SQL-Server can specify WITH CHECK/WITH NOCHECK
ADD CONSTRAINT FK_T_Room_T_Client FOREIGN KEY(RM_CLI_ID)
REFERENCES dbo.T_Client (CLI_ID)
ON DELETE CASCADE
Теперь вы можете сказать
DELETE FROM T_Client WHERE CLI_ID = x
и номера автоматически удаляются при удалении клиента.
Проблема решена - без изменений кода приложения.
Одно слово предостережения: в Microsoft SQL-Server это не сработает, если у вас есть таблица, которая ссылается сама. Поэтому, если вы попытаетесь определить каскад delete в рекурсивной древовидной структуре, например:
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_T_FMS_Navigation_T_FMS_Navigation]') AND parent_object_id = OBJECT_ID(N'[dbo].[T_FMS_Navigation]'))
ALTER TABLE [dbo].[T_FMS_Navigation] WITH CHECK ADD CONSTRAINT [FK_T_FMS_Navigation_T_FMS_Navigation] FOREIGN KEY([NA_NA_UID])
REFERENCES [dbo].[T_FMS_Navigation] ([NA_UID])
ON DELETE CASCADE
GO
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_T_FMS_Navigation_T_FMS_Navigation]') AND parent_object_id = OBJECT_ID(N'[dbo].[T_FMS_Navigation]'))
ALTER TABLE [dbo].[T_FMS_Navigation] CHECK CONSTRAINT [FK_T_FMS_Navigation_T_FMS_Navigation]
GO
это не сработает, потому что Microsoft-SQL-сервер не позволяет вам установить внешний ключ с ON DELETE CASCADE
на рекурсивную древовидную структуру. Одной из причин этого является то, что дерево возможно циклическое, и это может привести к тупиковой ситуации.
PostgreSQL, с другой стороны, может это сделать;
необходимо, чтобы дерево было нециклическим.
Если дерево циклически, вы получите ошибку времени выполнения.
В этом случае вам просто нужно реализовать функцию удаления самостоятельно.
Предупреждение:
Это означает, что вы больше не можете просто удалять и повторно вставлять таблицу клиентов, потому что, если вы сделаете это, он удалит все записи в «T_Room» ... (без дополнительных обновлений без дельта)