Как удалить основные записи детали, используя один sql? - PullRequest
4 голосов
/ 08 августа 2011

Использование Delphi 7 и interbase 7

Можно ли удалить основную подробную запись и все ее вложенные подробные записи в одном операторе SQL?

Пример:

Таблица1
ID - целое число
НАЗВАНИЕ - Varchar (80)

Таблица2
ID - целое число
Table1_ID - целое число
TITLE - Varchar (80)

Table3
ID - целое число
Table2_ID - Integer
TITLE - Varchar (80)

Я хочу удалить идентификатор 10 изTable1, и все соответствующие ему записи (Table1_ID) в таблице 2, и все соответствующие записи (Table2_ID) в таблице 3

Если я не могу сделать это в одном sql, как мне сделать это в несколькихsqls (правильная последовательность вызовов операторов)?

Ответы [ 6 ]

10 голосов
/ 08 августа 2011

Вы можете сделать это, удалив по порядку некоторые SQL, записи в Table3, table2 и table1. Все в одной транзакции, чтобы сделать это как «уникальная операция».

Одной из альтернатив является использование триггеров для удаления записи, связанной с таблицей 2, когда вы удаляете одну запись в таблице 1, и эквивалент в таблице 2 для удаления связанных записей в таблице 3.

Еще один (если позволяет вам DB) - использовать ON CASCADE DELETE (или аналогичный) для удаления связанных записей на tabla2 и table3, когда вы удаляете запись un table1 (см. Справку или документацию по вашей SGBD / базе данных).

Простите за ошибки с английским. Это не мой естественный язык.

Привет.

3 голосов
/ 08 августа 2011

Вы можете использовать внешние ключи для каскадного удаления дочерних записей при удалении родительской записи.

Следующая команда должна создать внешний ключ для удаления записей в Table2 (Table1_ID) при удалении записи в Table1 (ID).

ALTER TABLE TABLE2 ADD CONSTRAINT FK_TABLE2_TABLE1 
FOREIGN KEY (Table1_ID) REFERENCES TABLE1 (ID) 
ON DELETE CASCADE;

Таким образом ядро ​​базы данных заботится об удалениях в дочерних таблицах, поэтому все, что вам нужно сделать, это

delete from TABLE1 where ID = :ID_VALUE

С уважением,

1 голос
/ 10 августа 2011

В дополнение к ответам, уже приведенным с несколькими операторами SQL, связями внешнего ключа и триггерами.В InterBase вы также можете написать хранимую процедуру для удаления основной и подробной записей.Тогда вам понадобится только один оператор SQL в вашей программе.

Ниже приведены два вида хранимых процедур, которые вы можете использовать в этой ситуации.
Первый из них почти такой же, как ответ HeartWave, но затем в хранимомпроцедура.

CREATE PROCEDURE DELETEMASTERDETAIL_WITHOUTINFO(
    pMasterID INTEGER)
RETURNS (
    rResult INTEGER)
AS
declare variable vTable2ID integer;
begin
  /* don't return information about deleted records */
  rResult = 0;

  for select id
      from table2
      where table1_id = :pMasterID
      into :vTable2ID do
  begin
    delete from table3
    where table2_id = :vTable2ID;
  end

  delete from table2
  where table1_id = :pMasterID;

  delete from table1
  where id = :pMasterID;

  rResult = rResult + 1;

  suspend;
end

Оператор SQL для вызова этой хранимой процедуры:

select rresult
from deletemasterdetail_withoutinfo(:pMasterID)

Второй будет возвращать информацию о количестве удаленных записей в таблице.Я не знаю, если вам это нужно, но, возможно, это полезно для кого-то еще.Если поле идентификатора в Таблице 1 является первичным ключом, то первый оператор SELECT немного перегружен.

CREATE PROCEDURE DELETEMASTERDETAIL_WITHINFO(
    pMasterID INTEGER)
RETURNS (
    rTable1Deleted INTEGER,
    rTable2Deleted INTEGER,
    rTable3Deleted INTEGER)
AS
declare variable vTable1ID integer;
declare variable vTable2ID integer;
declare variable vTable3ID integer;
begin
  /* return information about deleted records */
  rTable1Deleted = 0;
  rTable2Deleted = 0;
  rTable3Deleted = 0;

  for select id
      from table1
      where id = :pMasterID
      into :vTable1ID do
  begin
    for select id
        from table2
        where table1_id = :vTable1ID
        into :vTable2ID do
    begin
      for select id
          from table3
          where table2_id = :vTable2ID
          into :vTable3ID do
      begin
        rTable3Deleted = rTable3Deleted + 1;

        delete from table3
        where id = :vTable3ID;
      end

      rTable2Deleted = rTable2Deleted + 1;
      delete from table2
      where id = :vTable2ID;
    end 

    rTable1Deleted = rTable1Deleted + 1;
    delete from table1
    where id = :vTable1ID;
  end

  suspend;
end

Оператор SQL для вызова этой хранимой процедуры:

select rtable1deleted, rtable2deleted, rtable3deleted
from deletemasterdetail_withinfo(:pMasterID)

BTW.Я почти всегда использую хотя бы один возвращаемый параметр в SP.Это позволит использовать компонент Query для вызова хранимой процедуры.
Если параметры результата отсутствуют, для выполнения SP должен использоваться компонент хранимой процедуры.

1 голос
/ 08 августа 2011

УДАЛИТЬ ИЗ Table3, ГДЕ Table2_ID IN (ВЫБЕРИТЕ ID ИЗ Table_2, ГДЕ Table1_ID = xxxx)

УДАЛИТЬ ИЗ Table2, ГДЕ Table1_ID = xxxx

УДАЛИТЬ ИЗ Таблицы1, ГДЕ ID = xxxx

1 голос
/ 08 августа 2011

Если вы создаете ссылки на внешний ключ с опцией каскада, удаление родительской записи также удалит все детали (если другие ограничения не препятствуют этому).

SQL:

ALTER TABLE Table2 ADD CONSTRAINT Table2_Table1_ID 
  FOREIGN KEY(Table1_ID) REFERENCES Table1(ID) ON DELETE CASCADE

Это решение делаетне требуя взаимодействия клиентских приложений, сервер будет поддерживать согласованность модели данных.

1 голос
/ 08 августа 2011

Вы не можете сделать это в одном операторе, но вместо этого вы можете использовать транзакции в Delphi, чтобы убедиться, что все или ни один из операторов не выполнен.

Если вы используете BDE, удалите компонент TDatabase, задайте свойства по умолчанию и напишите следующий код.

try
  Database1.StartTransaction;
  //Execute first query
  //Execute second query
  //Execute third query
  Database1.Commit;
except on E: Exception do
  Database1.Rollback;
end;

Если вы используете ADO, тогда используйте ADOConnection1.BeginTrans; ADOConnection1.CommitTrans; ADOConnection1.RollbackTrans; операторов

...