Поиск…


УДАЛИТЬ КАСКАД

Предположим, у вас есть приложение, которое администрирует комнаты.
Предположим также, что ваше приложение работает на основе клиента (арендатора).
У вас несколько клиентов.
Таким образом, ваша база данных будет содержать одну таблицу для клиентов и одну для комнат.

Теперь у каждого клиента есть 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» ... (без дополнительных обновлений без дельта)



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow