2008-09-22 10 views
32

Mam bazę danych klientów. Jest tak duży, że jest naprawdę uciążliwy w obsłudze, i wolałbym go zmniejszyć do 10% klientów, co jest wystarczające do rozwoju. Mam strasznie dużo stołów i nie chcę ich modyfikować za pomocą "NA KASKADOWANIU", zwłaszcza, że ​​jest to jednorazowa transakcja.W programie SQL Server 2005, czy mogę wykonać usuwanie kaskadowe bez ustawiania właściwości w tabelach?

Czy mogę wykonać operację usuwania, która przepływa przez wszystkie moje tabele bez ich wcześniejszego skonfigurowania? Jeśli nie, jaka jest moja najlepsza opcja?

Odpowiedz

52

Łącząc swoje rady i skrypt znalazłem w Internecie, zrobiłem procedurę, która będzie produkować SQL można uruchomić aby przeprowadzić kaskadowe usuwanie niezależnie od ON DELETE CASCADE. To była prawdopodobnie strata czasu, ale dobrze się spisałem. Zaletą robienia tego w ten sposób jest umieszczenie między każdą linią instrukcji GO i nie musi to być jedna duża transakcja. Oryginał był procedurą rekurencyjną; ten rozwinie rekursję do tabeli stosów.

create procedure usp_delete_cascade (
    @base_table_name varchar(200), @base_criteria nvarchar(1000) 
) 
as begin 
    -- Adapted from http://www.sqlteam.com/article/performing-a-cascade-delete-in-sql-server-7 
    -- Expects the name of a table, and a conditional for selecting rows 
    -- within that table that you want deleted. 
    -- Produces SQL that, when run, deletes all table rows referencing the ones 
    -- you initially selected, cascading into any number of tables, 
    -- without the need for "ON DELETE CASCADE". 
    -- Does not appear to work with self-referencing tables, but it will 
    -- delete everything beneath them. 
    -- To make it easy on the server, put a "GO" statement between each line. 

    declare @to_delete table (
     id int identity(1, 1) primary key not null, 
     criteria nvarchar(1000) not null, 
     table_name varchar(200) not null, 
     processed bit not null, 
     delete_sql varchar(1000) 
    ) 

    insert into @to_delete (criteria, table_name, processed) values (@base_criteria, @base_table_name, 0) 

    declare @id int, @criteria nvarchar(1000), @table_name varchar(200) 
    while exists(select 1 from @to_delete where processed = 0) begin 
     select top 1 @id = id, @criteria = criteria, @table_name = table_name from @to_delete where processed = 0 order by id desc 

     insert into @to_delete (criteria, table_name, processed) 
      select referencing_column.name + ' in (select [' + referenced_column.name + '] from [' + @table_name +'] where ' + @criteria + ')', 
       referencing_table.name, 
       0 
      from sys.foreign_key_columns fk 
       inner join sys.columns referencing_column on fk.parent_object_id = referencing_column.object_id 
        and fk.parent_column_id = referencing_column.column_id 
       inner join sys.columns referenced_column on fk.referenced_object_id = referenced_column.object_id 
        and fk.referenced_column_id = referenced_column.column_id 
       inner join sys.objects referencing_table on fk.parent_object_id = referencing_table.object_id 
       inner join sys.objects referenced_table on fk.referenced_object_id = referenced_table.object_id 
       inner join sys.objects constraint_object on fk.constraint_object_id = constraint_object.object_id 
      where referenced_table.name = @table_name 
       and referencing_table.name != referenced_table.name 

     update @to_delete set 
      processed = 1 
     where id = @id 
    end 

    select 'print ''deleting from ' + table_name + '...''; delete from [' + table_name + '] where ' + criteria from @to_delete order by id desc 
end 

exec usp_delete_cascade 'root_table_name', 'id = 123' 
+0

Niezły scenariusz! Dziękuję Ci! – splattne

+0

czy ten skrypt pozwoliłby mi wysłać na przykład "code = ABC AND name = dave" – ThePower

+1

To było trochę, ale tak myślę! –

2

Zwykle po prostu ręcznie wpisuję zapytania, aby usunąć niepotrzebne rekordy i zapisać je jako plik .sql do wykorzystania w przyszłości. Pseudokod jest:

  1. wybierz id-tych rekordów z głównej tabeli, które chcę usunąć w tabeli temp
  2. Napisać DELETE dla każdej powiązanej tabeli, która łączy do tabeli temp.
  3. Napisz kwerendę usuwania dla tabeli głównej, dołączając do mojej tabeli temp.
2

Moja propozycja to napisać skrypt, który doda kaskadę kasowania do każdego związku w bazie danych podczas eksportowania listy zmodyfikowanych relacji. Następnie można odwrócić proces i usunąć polecenie kasowania kasowania na każdej tabeli na liście.

2

Osobiście, jeśli zamierzasz zostawić zapisy w produkcji, pozostawiłbym je również w fazie rozwoju. W przeciwnym razie możesz napisać kod, który działa poprawnie, gdy zestaw rekordów jest mały, ale przekracza limit czasu w obliczu prawdziwego zestawu rekordów.

Ale jeśli jesteś zdecydowany to zrobić, skopiowałbym pole id rekordów, które chcesz wykryć z głównej tabeli do tabeli roboczej. Następnie wziąłbym każdą powiązaną ze sobą tabelę i zapisałbym połączenie łączące się z tym miejscem roboczym, aby usunąć tylko te rekordy. Zakończ z tabelą nadrzędną. Upewnij się, że jest to napisane w skrypcie i zapisane, więc następnym razem, gdy chcesz zrobić coś podobnego do danych testowych, możesz z łatwością go uruchomić bez konieczności wymyślania tabel, które wymagają usunięcia rekordów.

5

Przejdź do SQL Server Management Studio i kliknij prawym przyciskiem myszy bazę danych. Wybierz Zadania-> Wygeneruj skrypty. Kliknij dwa razy przycisk Dalej. W oknie Opcje wybierz ustawienie, aby generować tylko instrukcje CREATE, i ustaw wszystko na False, z wyjątkiem Foreign Keys. Kliknij Następny. Wybierz Tabele i ponownie kliknij przycisk Dalej. Kliknij przycisk "Wybierz wszystko" i kliknij Dalej, a następnie Zakończ i wyślij skrypt do wyboru okna zapytania lub pliku (nie używaj schowka, ponieważ może to być duży skrypt). Teraz usuń cały skrypt dodający tabele i powinieneś pozostawić skrypt, aby utworzyć klucze obce.

Wykonaj kopię tego skryptu, ponieważ przywróci ona jego bieżący stan. Użyj wyszukiwania i zamiany, aby dodać NA KASKADĘ na końcu każdego ograniczenia. Może się to różnić w zależności od konfiguracji FK i konieczności ręcznej edycji.

Powtórz generowanie skryptu, ale tym razem ustaw go tak, aby generował tylko instrukcje DROP. Pamiętaj, aby ręcznie usunąć spadki tabeli, które zostały wygenerowane. Uruchom kropelki, a następnie uruchom edytowane tworzenie, aby je wszystkie usuwały kaskadowo. Wykonaj usuwanie, uruchom ponownie skrypt upuszczania, a następnie uruchom skrypt, który został zapisany na początku.

Również - MAKE A BACKUP TWÓJ DB PIERWSZY! Nawet jeśli jest to po prostu baza danych deweloperów, zaoszczędzi ci trochę bólu głowy, jeśli część skryptu nie jest w porządku.

Mam nadzieję, że to pomoże!

BTW - zdecydowanie powinieneś zrobić test z pełnymi danymi testowymi, jak sugerował inny plakat, ale widzę, dlaczego nie potrzebujesz tego do początkowego rozwoju. Po prostu nie zapomnij uwzględnić tego jako części QA w pewnym momencie.

7

Chyba że chcesz zachować wszystkie powiązane zapytania, zgodnie z propozycją Chrisa, ON DELETE CASCADE jest zdecydowanie najszybszym i najbardziej bezpośrednim rozwiązaniem. A jeśli nie ma to być trwałe, dlaczego nie masz kodu T-SQL, które będzie przełączyć tę opcję włączania i wyłączania jak tutaj

  1. usunąć oryginalną Tbl_A_MyFK ograniczenie (bez ON DELETE CASCADE)

    ALTER TABLE Tbl_A DROP CONSTRAINT Tbl_A_MyFK

  2. ustawić ograniczenie Tbl_A_MyFK z ON DELETE CASCADE

    ALTER TABLE Tbl_A ADD CONSTRAINT Tbl_A_MyFK FOREIGN KEY (MyFK) REFERENCES Tbl_B(Column) ON DELETE CASCADE

  3. Tutaj można zrobić swoją kasowania

    DELETE FROM Tbl_A WHERE ...

  4. upuścić ograniczenie Tbl_A_MyFK

    ALTER TABLE Tbl_A DROP CONSTRAINT Tbl_A_MyFK

  5. ustawić ograniczenie Tbl_A_MyFK bez ON DELETE CASCADE

    ALTER TABLE Tbl_A ADD CONSTRAINT Tbl_A_MyFK FOREIGN KEY (MyFK) REFERENCES (Tbl_B)

1

po wybraniu trzeba zbudować i uruchomić rzeczywiste usunięcie

declare @deleteSql nvarchar(1200) 
declare delete_cursor cursor for 
select table_name, criteria 
from @to_delete 
order by id desc 

open delete_cursor 

fetch next from delete_cursor 
into @table_name, @criteria 

while @@fetch_status = 0 
begin 
select @deleteSql = 'delete from ' + @table_name + ' where ' + @criteria 
--print @deleteSql 
-- exec sp_execute @deleteSql 
EXEC SP_EXECUTESQL @deleteSql 

fetch next from delete_cursor 
into @table_name, @criteria 
end 
close delete_cursor 
deallocate delete_cursor 
+0

dodać to po instrukcji select – dan

2

Biorąc zaakceptowane odpowiedź nieco dalej, miałem potrzebę zrobienia tego w poprzek stołów w różnych schematów. Zaktualizowałem skrypt, aby uwzględnić schemat w wyjściowych skryptach usuwania.

CREATE PROCEDURE usp_delete_cascade (
     @base_table_schema varchar(100), @base_table_name varchar(200), @base_criteria nvarchar(1000) 
) 
as begin 

     -- Expects the name of a table, and a conditional for selecting rows 
     -- within that table that you want deleted. 
     -- Produces SQL that, when run, deletes all table rows referencing the ones 
     -- you initially selected, cascading into any number of tables, 
     -- without the need for "ON DELETE CASCADE". 
     -- Does not appear to work with self-referencing tables, but it will 
     -- delete everything beneath them. 
     -- To make it easy on the server, put a "GO" statement between each line. 

     declare @to_delete table (
       id int identity(1, 1) primary key not null, 
       criteria nvarchar(1000) not null, 
       table_schema varchar(100), 
       table_name varchar(200) not null, 
       processed bit not null, 
       delete_sql varchar(1000) 
     ) 

     insert into @to_delete (criteria, table_schema, table_name, processed) values (@base_criteria, @base_table_schema, @base_table_name, 0) 

     declare @id int, @criteria nvarchar(1000), @table_name varchar(200), @table_schema varchar(100) 
     while exists(select 1 from @to_delete where processed = 0) begin 
       select top 1 @id = id, @criteria = criteria, @table_name = table_name, @table_schema = table_schema from @to_delete where processed = 0 order by id desc 

       insert into @to_delete (criteria, table_schema, table_name, processed) 
         select referencing_column.name + ' in (select [' + referenced_column.name + '] from [' + @table_schema + '].[' + @table_name +'] where ' + @criteria + ')', 
           schematable.name, 
           referencing_table.name, 
           0 
         from sys.foreign_key_columns fk 
           inner join sys.columns referencing_column on fk.parent_object_id = referencing_column.object_id 
             and fk.parent_column_id = referencing_column.column_id 
           inner join sys.columns referenced_column on fk.referenced_object_id = referenced_column.object_id 
             and fk.referenced_column_id = referenced_column.column_id 
           inner join sys.objects referencing_table on fk.parent_object_id = referencing_table.object_id 
           inner join sys.schemas schematable on referencing_table.schema_id = schematable.schema_id 
           inner join sys.objects referenced_table on fk.referenced_object_id = referenced_table.object_id 
           inner join sys.objects constraint_object on fk.constraint_object_id = constraint_object.object_id 
         where referenced_table.name = @table_name 
           and referencing_table.name != referenced_table.name 

       update @to_delete set 
         processed = 1 
       where id = @id 
     end 

     select 'print ''deleting from ' + table_name + '...''; delete from [' + table_schema + '].[' + table_name + '] where ' + criteria from @to_delete order by id desc 
end 

exec usp_delete_cascade 'schema', 'RootTable', 'Id = 123' 
exec usp_delete_cascade 'schema', 'RootTable', 'GuidId = ''A7202F84-FA57-4355-B499-1F8718E29058''' 
2

Kevin post jest niekompletny, jego t-sql sp drukuje tylko polecenie, aby wykonać te polecenia, przedostatni koniec dodać

DECLARE @commandText VARCHAR(8000) 
     DECLARE curDeletes CURSOR FOR 
      select 'delete from [' + table_name + '] where ' + criteria from @to_delete order by id desc 

     OPEN curDeletes 
     FETCH NEXT FROM curDeletes 
     INTO 
      @commandText 

     WHILE(@@FETCH_STATUS=0) 
     BEGIN 
      EXEC (@commandText) 
      FETCH NEXT FROM curDeletes INTO @commandText 
     END 
     CLOSE curDeletes 
     DEALLOCATE curDeletes 
5

Oto wersji zaakceptowanej odpowiedzi zoptymalizowana dla słabo zaludnionych modele danych. Sprawdza istnienie danych w łańcuchu FK przed dodaniem go do listy usunięć.Używam go do czyszczenia danych testowych.

Nie należy go używać w aktywnym systemie transakcyjnym db - będzie przechowywać zbyt długo blokady.

/* 
-- ============================================================================ 
-- Purpose: Performs a cascading hard-delete. 
--   Not for use on an active transactional database- it holds locks for too long. 
--   (http://stackoverflow.com/questions/116968/in-sql-server-2005-can-i-do-a-cascade-delete-without-setting-the-property-on-my) 
-- eg: 
exec dbo.hp_Common_Delete 'tblConsumer', 'Surname = ''TestDxOverdueOneReviewWm''', 1 
-- ============================================================================ 
*/ 
create proc [dbo].[hp_Common_Delete] 
(
    @TableName sysname, 
    @Where nvarchar(4000), -- Shouldn't include 'where' keyword, e.g. Surname = 'smith', NOT where Surname = 'smith' 
    @IsDebug bit = 0 
) 
as 
set nocount on 

begin try 
    -- Prepare tables to store deletion criteria. 
    -- #tmp_to_delete stores criteria that is tested for results before being added to #to_delete 
    create table #to_delete 
    (
     id int identity(1, 1) primary key not null, 
     criteria nvarchar(4000) not null, 
     table_name sysname not null, 
     processed bit not null default(0) 
    ) 
    create table #tmp_to_delete 
    (
     id int primary key identity(1,1), 
     criteria nvarchar(4000) not null, 
     table_name sysname not null 
    ) 

    -- Open a transaction (it'll be a long one- don't use this on production!) 
    -- We need a transaction around criteria generation because we only 
    -- retain criteria that has rows in the db, and we don't want that to change under us. 
    begin tran 
     -- If the top-level table meets the deletion criteria, add it 
     declare @Sql nvarchar(4000) 
     set @Sql = 'if exists(select top(1) * from ' + @TableName + ' where ' + @Where + ') 
      insert #to_delete (criteria, table_name) values (''' + replace(@Where, '''', '''''') + ''', ''' + @TableName + ''')' 
     exec (@Sql) 

     -- Loop over deletion table, walking foreign keys to generate delete targets 
     declare @id int, @tmp_id int, @criteria nvarchar(4000), @new_criteria nvarchar(4000), @table_name sysname, @new_table_name sysname 
     while exists(select 1 from #to_delete where processed = 0) 
     begin 
      -- Grab table/criteria to work on 
      select top(1) @id = id, 
        @criteria = criteria, 
        @table_name = table_name 
      from #to_delete 
      where processed = 0 
      order by id desc 

      -- Insert all immediate child tables into a temp table for processing 
      insert #tmp_to_delete 
      select referencing_column.name + ' in (select [' + referenced_column.name + '] from [' + @table_name +'] where ' + @criteria + ')', 
        referencing_table.name 
      from sys.foreign_key_columns fk 
        inner join sys.columns referencing_column on fk.parent_object_id = referencing_column.object_id 
          and fk.parent_column_id = referencing_column.column_id 
        inner join sys.columns referenced_column on fk.referenced_object_id = referenced_column.object_id 
          and fk.referenced_column_id = referenced_column.column_id 
        inner join sys.objects referencing_table on fk.parent_object_id = referencing_table.object_id 
        inner join sys.objects referenced_table on fk.referenced_object_id = referenced_table.object_id 
        inner join sys.objects constraint_object on fk.constraint_object_id = constraint_object.object_id 
      where referenced_table.name = @table_name 
        and referencing_table.name != referenced_table.name 

      -- Loop on child table criteria, and insert them into delete table if they have records in the db 
      select @tmp_id = max(id) from #tmp_to_delete 
      while (@tmp_id >= 1) 
      begin 
       select @new_criteria = criteria, @new_table_name = table_name from #tmp_to_delete where id = @tmp_id 
       set @Sql = 'if exists(select top(1) * from ' + @new_table_name + ' where ' + @new_criteria + ') 
        insert #to_delete (criteria, table_name) values (''' + replace(@new_criteria, '''', '''''') + ''', ''' + @new_table_name + ''')' 
       exec (@Sql) 

       set @tmp_id = @tmp_id - 1 
      end 
      truncate table #tmp_to_delete 

      -- Move to next record 
      update #to_delete 
      set  processed = 1 
      where id = @id 
     end 

     -- We have a list of all tables requiring deletion. Actually delete now. 
     select @id = max(id) from #to_delete 
     while (@id >= 1) 
     begin 
      select @criteria = criteria, @table_name = table_name from #to_delete where id = @id 
      set @Sql = 'delete from [' + @table_name + '] where ' + @criteria 
      if (@IsDebug = 1) print @Sql 
      exec (@Sql) 

      -- Next record 
      set @id = @id - 1 
     end 
    commit 
end try 

begin catch 
    -- Any error results in a rollback of the entire job 
    if (@@trancount > 0) rollback 

    declare @message nvarchar(2047), @errorProcedure nvarchar(126), @errorMessage nvarchar(2048), @errorNumber int, @errorSeverity int, @errorState int, @errorLine int 
    select @errorProcedure = isnull(error_procedure(), N'hp_Common_Delete'), 
      @errorMessage = isnull(error_message(), N'hp_Common_Delete unable to determine error message'), 
      @errorNumber = error_number(), @errorSeverity = error_severity(), @errorState = error_state(), @errorLine = error_line() 

    -- Prepare error information as it would be output in SQL Mgt Studio 
    declare @event nvarchar(2047) 
    select @event = 'Msg ' + isnull(cast(@errorNumber as varchar), 'null') + 
         ', Level ' + isnull(cast(@errorSeverity as varchar), 'null') + 
         ', State ' + isnull(cast(@errorState as varchar), 'null') + 
         ', Procedure ' + isnull(@errorProcedure, 'null') + 
         ', Line ' + isnull(cast(@errorLine as varchar), 'null') + 
         ': ' + isnull(@errorMessage, '@ErrorMessage null') 
    print @event 

    -- Re-raise error to ensure admin/job runners understand there was a failure 
    raiserror(@errorMessage, @errorSeverity, @errorState) 
end catch 
2

Rozbudowa odpowiedź croisharp do podjęcia wyzwalaczy pod uwagę, to jest świadomy schematu rozwiązanie, które wyłącza wszystkie wpływające wyzwalacze, usuwa wiersze i umożliwia wyzwala.

CREATE PROCEDURE usp_delete_cascade (
@base_table_schema varchar(100), 
@base_table_name varchar(200), 
@base_criteria nvarchar(1000) 
) 
as begin 

    -- Expects the name of a table, and a conditional for selecting rows 
    -- within that table that you want deleted. 
    -- Produces SQL that, when run, deletes all table rows referencing the ones 
    -- you initially selected, cascading into any number of tables, 
    -- without the need for "ON DELETE CASCADE". 
    -- Does not appear to work with self-referencing tables, but it will 
    -- delete everything beneath them. 
    -- To make it easy on the server, put a "GO" statement between each line. 

    declare @to_delete table (
      id int identity(1, 1) primary key not null, 
      criteria nvarchar(1000) not null, 
      table_schema varchar(100), 
      table_name varchar(200) not null, 
      processed bit not null, 
      delete_sql varchar(1000) 
    ) 

    insert into @to_delete (criteria, table_schema, table_name, processed) values (@base_criteria, @base_table_schema, @base_table_name, 0) 

    declare @id int, @criteria nvarchar(1000), @table_name varchar(200), @table_schema varchar(100) 
    while exists(select 1 from @to_delete where processed = 0) begin 
      select top 1 @id = id, @criteria = criteria, @table_name = table_name, @table_schema = table_schema from @to_delete where processed = 0 order by id desc 

      insert into @to_delete (criteria, table_schema, table_name, processed) 
        select referencing_column.name + ' in (select [' + referenced_column.name + '] from [' + @table_schema + '].[' + @table_name +'] where ' + @criteria + ')', 
          schematable.name, 
          referencing_table.name, 
          0 
        from sys.foreign_key_columns fk 
          inner join sys.columns referencing_column on fk.parent_object_id = referencing_column.object_id 
            and fk.parent_column_id = referencing_column.column_id 
          inner join sys.columns referenced_column on fk.referenced_object_id = referenced_column.object_id 
            and fk.referenced_column_id = referenced_column.column_id 
          inner join sys.objects referencing_table on fk.parent_object_id = referencing_table.object_id 
          inner join sys.schemas schematable on referencing_table.schema_id = schematable.schema_id 
          inner join sys.objects referenced_table on fk.referenced_object_id = referenced_table.object_id 
          inner join sys.objects constraint_object on fk.constraint_object_id = constraint_object.object_id 
        where referenced_table.name = @table_name 
          and referencing_table.name != referenced_table.name 

      update @to_delete set 
        processed = 1 
      where id = @id 
    end 

    select 'print ''deleting from ' + table_name + '...''; delete from [' + table_schema + '].[' + table_name + '] where ' + criteria from @to_delete order by id desc 

    DECLARE @commandText VARCHAR(8000), @triggerOn VARCHAR(8000), @triggerOff VARCHAR(8000) 
    DECLARE curDeletes CURSOR FOR 
     select 
      'DELETE FROM [' + table_schema + '].[' + table_name + '] WHERE ' + criteria, 
      'ALTER TABLE [' + table_schema + '].[' + table_name + '] DISABLE TRIGGER ALL', 
      'ALTER TABLE [' + table_schema + '].[' + table_name + '] ENABLE TRIGGER ALL' 
     from @to_delete order by id desc 

    OPEN curDeletes 
    FETCH NEXT FROM curDeletes INTO @commandText, @triggerOff, @triggerOn 

    WHILE(@@FETCH_STATUS=0) 
    BEGIN 
     EXEC (@triggerOff) 
     EXEC (@commandText) 
     EXEC (@triggerOn) 
     FETCH NEXT FROM curDeletes INTO @commandText, @triggerOff, @triggerOn 
    END 
    CLOSE curDeletes 
    DEALLOCATE curDeletes 
end 
0

Ten skrypt ma dwa problemy: 1. musi wskazać warunek 1 = 1, aby skasować wszystkie podstawa stołu. 2. Stwarza to bezpośrednie relacje tylko z tabelą podstawową. Jeśli końcowy stół ma inny związek tabeli macierzysty, którego kasowania nie

USUŃ Z [dbo]. [Tabela 2] gdzie tableid w (wybierz [id] z [dbo]. [Table3] gdzie 1 = 1)

Jeśli tabela 2 ma tabelę relacji rodzica1

1

Opublikuj tutaj skrypt, który będzie działał z kluczami obcymi zawiera więcej niż jedną kolumnę.

create procedure usp_delete_cascade (
@TableName varchar(200), @Where nvarchar(1000) 
) as begin 

declare @to_delete table (
    id int identity(1, 1) primary key not null, 
    criteria nvarchar(1000) not null, 
    table_name varchar(200) not null, 
    processed bit not null default(0), 
    delete_sql varchar(1000) 
) 
      DECLARE @MyCursor CURSOR 

declare   @referencing_column_name varchar(1000) 
declare   @referencing_table_name varchar(1000) 
declare @Sql nvarchar(4000) 
insert into @to_delete (criteria, table_name) values ('', @TableName) 


declare @id int, @criteria nvarchar(1000), @table_name varchar(200) 
while exists(select 1 from @to_delete where processed = 0) begin 
    select top 1 @id = id, @criteria = criteria, @table_name = table_name from @to_delete where processed = 0 order by id desc 
     SET @MyCursor = CURSOR FAST_FORWARD 
     FOR 
     select referencing_column.name as column_name, 
      referencing_table.name as table_name 
     from sys.foreign_key_columns fk 
      inner join sys.columns referencing_column on fk.parent_object_id = referencing_column.object_id 
       and fk.parent_column_id = referencing_column.column_id 
      inner join sys.columns referenced_column on fk.referenced_object_id = referenced_column.object_id 
       and fk.referenced_column_id = referenced_column.column_id 
      inner join sys.objects referencing_table on fk.parent_object_id = referencing_table.object_id 
      inner join sys.objects referenced_table on fk.referenced_object_id = referenced_table.object_id 
      inner join sys.objects constraint_object on fk.constraint_object_id = constraint_object.object_id 
     where referenced_table.name = @table_name 
      and referencing_table.name != referenced_table.name 

     OPEN @MyCursor 
     FETCH NEXT FROM @MYCursor 
     INTO @referencing_column_name, @referencing_table_name 

     WHILE @@FETCH_STATUS = 0 

     BEGIN 
      PRINT @referencing_column_name 
      PRINT @referencing_table_name 
        update @to_delete set criteria = criteria + ' AND '[email protected]_name+'.'[email protected]_column_name+'='+ @referencing_table_name+'.'[email protected]_column_name 
        where table_name = @referencing_table_name 

        if(@@ROWCOUNT = 0) 
        BEGIN 
          --if(@id <> 1) 
          --BEGIN 
           insert into @to_delete (criteria, table_name) 
           VALUES(' LEFT JOIN '[email protected]_name+' ON '[email protected]_name+'.'[email protected]_column_name+'='+ @referencing_table_name+'.'[email protected]_column_name+ @criteria, 
           @referencing_table_name 
           ) 
          --END 
          --ELSE 
          --BEGIN 
           --insert into @to_delete (criteria, table_name) 
           --VALUES(' LEFT JOIN '[email protected]_name+' ON '[email protected]_name+'.'[email protected]_column_name+'='+ @referencing_table_name+'.'[email protected]_column_name, 
           [email protected]_table_name 
           --) 
          --END 
        END 
         FETCH NEXT FROM @MYCursor 
      INTO @referencing_column_name, @referencing_table_name 
     END 


     CLOSE @MyCursor 
     DEALLOCATE @MyCursor 
    update @to_delete set 
     processed = 1 
    where id = @id 
end 

--select 'print ''deleting from ' + table_name + '...''; delete from [' + table_name + '] where ' + criteria from @to_delete order by id desc 

--select id, table_name, criteria, @Where from @to_delete order by id desc 

select @id = max(id) from @to_delete 
while (@id >= 1) 
begin 
    select @criteria = criteria, @table_name = table_name from @to_delete where id = @id 
    set @Sql = 'delete [' + @table_name + '] from [' + @table_name + '] ' + @criteria+' WHERE '[email protected] 
    exec (@Sql) 
    PRINT @Sql 

    -- Next record 
    set @id = @id - 1 
end 
end