При работе с реляционными базами данных на языке программирования Delphi часто возникает задача удаления записей, связанных между собой зависимостями "один ко многим". Это означает, что из одной таблицы (родительской) данные ссылаются на записи в одной или нескольких других таблицах (дочерних). Удаление такой записи требует последовательного удаления всех связанных записей, чтобы избежать нарушения целостности данных.
Проблема
Рассмотрим пример с тремя таблицами: Table1, Table2 и Table3. Table1 является родительской таблицей, Table2 и Table3 - дочерними, ссылающимися на Table1.
Table1: ID (Integer), TITLE (Varchar(80))
Table2: ID (Integer), Table1_ID (Integer), TITLE (Varchar(80))
Table3: ID (Integer), Table2_ID (Integer), TITLE (Varchar(80))
Задача состоит в том, чтобы удалить запись с ID = 10 из Table1 и все связанные записи из Table2 и Table3.
Решение
Для удаления записей с зависимостями "один ко многим" можно использовать транзакции, чтобы гарантировать, что все связанные записи будут удалены или ни одна. Также можно использовать каскадное удаление через внешние ключи.
Использование каскадного удаления
Создание внешних ключей с опцией каскадного удаления позволит автоматически удалять дочерние записи при удалении родительской.
ALTER TABLE Table2 ADD CONSTRAINT FK_Table2_Table1
FOREIGN KEY (Table1_ID) REFERENCES Table1 (ID)
ON DELETE CASCADE;
Теперь, удаляя запись из Table1, все связанные записи в Table2 и Table3 будут удалены автоматически.
Использование транзакций
Если каскадное удаление недоступно или нежелательно, можно использовать транзакции для выполнения нескольких SQL-запросов.
try
Database1.StartTransaction;
try
// Удаление записей из Table3
Database1.SQL.Clear;
Database1.SQL.Add('DELETE FROM Table3 WHERE Table2_ID IN (SELECT ID FROM Table2 WHERE Table1_ID = :MasterID)');
Database1.SQL.AddParam('MasterID', masterID);
Database1.ExecSQL;
// Удаление записей из Table2
Database1.SQL.Clear;
Database1.SQL.Add('DELETE FROM Table2 WHERE Table1_ID = :MasterID');
Database1.SQL.AddParam('MasterID', masterID);
Database1.ExecSQL;
// Удаление записи из Table1
Database1.SQL.Clear;
Database1.SQL.Add('DELETE FROM Table1 WHERE ID = :MasterID');
Database1.SQL.AddParam('MasterID', masterID);
Database1.ExecSQL;
Database1.Commit;
except
on E: Exception do
begin
Database1.Rollback;
raise;
end;
end;
Использование хранимых процедур
В InterBase также можно создать хранимую процедуру для удаления записей.
CREATE PROCEDURE DeleteMasterDetail(IN pMasterID INT)
RETURNS (rResult INT)
AS
BEGIN
-- Удаление записей из Table3
DELETE FROM Table3 WHERE Table2_ID IN (SELECT ID FROM Table2 WHERE Table1_ID = pMasterID);
-- Удаление записей из Table2
DELETE FROM Table2 WHERE Table1_ID = pMasterID;
-- Удаление записи из Table1
DELETE FROM Table1 WHERE ID = pMasterID;
-- Возвращаем результат (например, количество удалённых записей)
rResult := 1;
SUSPEND;
END;
Теперь для удаления записи достаточно вызвать эту процедуру.
При работе с зависимостями "один ко многим" важно соблюдать последовательность удаления записей, чтобы избежать потери данных. Использование транзакций, каскадного удаления и хранимых процедур позволяет решить эту задачу эффективно.
Удаление записей с зависимостями 'один ко многим' в реляционных базах данных на Delphi требует последовательного удаления связанных записей для сохранения целостности данных.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS