web-dev-qa-db-fra.com

Dans SQL Server 2005, puis-je effectuer une suppression en cascade sans définir la propriété sur mes tables?

J'ai une base de données pleine de données clients. Il est si grand qu'il est vraiment lourd à utiliser, et je préfère simplement le réduire à 10% des clients, ce qui est beaucoup à développer. J'ai énormément de tables et je ne veux pas toutes les modifier avec "ON DELETE CASCADE", surtout parce que c'est une affaire unique.

Puis-je effectuer une opération de suppression qui se répercute en cascade sur toutes mes tables sans les configurer au préalable? Sinon, quelle est ma meilleure option?

36
Kevin Conner

En combinant vos conseils et un script que j'ai trouvé en ligne, j'ai créé une procédure qui produira du SQL que vous pouvez exécuter pour effectuer une suppression en cascade indépendamment de ON DELETE CASCADE. C'était probablement une grosse perte de temps, mais j'ai passé un bon moment à l'écrire. Un avantage de procéder de cette façon est que vous pouvez mettre une instruction GO entre chaque ligne, et cela ne doit pas être une grosse transaction. L'original était une procédure récursive; celui-ci déroule la récursivité dans une table de pile.

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'
55
Kevin Conner

Voici une version de la réponse acceptée optimisée pour les modèles de données peu peuplés. Il vérifie l'existence de données dans une chaîne FK avant de les ajouter à la liste de suppression. Je l'utilise pour nettoyer les données de test.

Ne l'utilisez pas dans une base de données transactionnelle active - elle maintiendra les verrous trop longtemps.

/*
-- ============================================================================
-- 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
7
Neil

À moins que vous ne souhaitiez conserver toutes les requêtes associées telles que proposées par Chris, ON DELETE CASCADE est de loin la solution la plus rapide et la plus directe. Et si vous ne voulez pas qu'il soit permanent, pourquoi n'avez-vous pas de code T-SQL qui activera et désactivera cette option comme ici

  1. supprimer la contrainte Tbl_A_MyFK d'origine (sans la fonction ON DELETE CASCADE)

    ALTER TABLE Tbl_A DROP CONSTRAINT Tbl_A_MyFK

  2. définissez la contrainte Tbl_A_MyFK avec ON DELETE CASCADE

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

  3. Ici vous pouvez faire votre suppression

    DELETE FROM Tbl_A WHERE ...

  4. laissez tomber votre contrainte Tbl_A_MyFK

    ALTER TABLE Tbl_A DROP CONSTRAINT Tbl_A_MyFK

  5. définissez la contrainte Tbl_A_MyFK sans le ON DELETE CASCADE

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

7
Philippe Grondier

Accédez à SQL Server Management Studio et cliquez avec le bouton droit sur la base de données. Sélectionnez Tâches-> Générer des scripts. Cliquez deux fois sur Suivant. Dans la fenêtre Options, choisissez de le définir pour générer des instructions CREATE uniquement et définissez tout sur False, à l'exception des clés étrangères. Cliquez sur Suivant. Sélectionnez Tables et cliquez à nouveau sur Suivant. Cliquez sur le bouton "Sélectionner tout" et cliquez sur Suivant puis sur Terminer et envoyez le script à votre choix d'une fenêtre ou d'un fichier de requête (n'utilisez pas le presse-papiers, car il pourrait s'agir d'un gros script). Maintenant, supprimez tout le script qui ajoute les tables et vous devriez vous retrouver avec un script pour créer vos clés étrangères.

Faites une copie de ce script car c'est ainsi que vous restaurerez votre base de données dans son état actuel. Utilisez une recherche et remplacez pour ajouter ON DELETE CASCADE à la fin de chaque contrainte. Cela peut varier en fonction de la configuration actuelle de vos FK et vous devrez peut-être effectuer des modifications manuelles.

Répétez la génération du script, mais cette fois, définissez-le pour générer uniquement des instructions DROP. Assurez-vous de supprimer manuellement les pertes de table générées. Exécutez les drops, puis exécutez vos créations modifiées pour les faire toutes en cascade lors de la suppression. Effectuez vos suppressions, réexécutez le script de suppression, puis exécutez le script que vous avez enregistré au début.

Aussi - FAITES UNE SAUVEGARDE DE VOTRE DB EN PREMIER! Même s'il ne s'agit que d'une base de données de développement, cela vous évitera des maux de tête si une partie du script ne vous convient pas.

J'espère que cela t'aides!

BTW - vous devriez certainement faire quelques tests avec vos données de test complètes comme l'a suggéré une autre affiche, mais je peux voir pourquoi vous pourriez ne pas avoir besoin de cela pour le développement initial. N'oubliez pas d'inclure cela dans le cadre de l'AQ à un moment donné.

5
Tom H

Habituellement, je viens d'écrire à la main les requêtes pour supprimer les enregistrements dont je ne veux pas et les enregistrer en tant que fichier .sql pour référence future. Le pseudocode est:

  1. sélectionner les identifiants des enregistrements de la table principale que je souhaite supprimer dans une table temporaire
  2. écrire une requête de suppression pour chaque table associée qui rejoint la table temporaire.
  3. écrire une requête de suppression pour la table principale se joignant à ma table temporaire.
2
NotMe

Ma suggestion est d'aller de l'avant et d'écrire un script qui ajoutera la cascade de suppression à chaque relation dans la base de données tout en exportant une liste de relations modifiées. Vous pouvez ensuite inverser le processus et supprimer la commande on delete cascade sur chaque table de la liste.

2
Orion Adrian

Personnellement, si vous allez laisser les disques en production, je les laisserais aussi en développement. Sinon, vous pouvez écrire du code qui fonctionne correctement lorsque le jeu d'enregistrements est petit mais arrive à expiration lorsqu'il est confronté au vrai jeu d'enregistrements.

Mais si vous êtes déterminé à le faire, je copierais d'abord le champ id des enregistrements que vous souhaitez détacher de la table principale vers une table de travail. Ensuite, je prenais chaque table associée et écrivais une suppression de jointure à cette table de travail pour supprimer uniquement ces enregistrements. Terminez avec la table parent. Assurez-vous que ceci est écrit dans un script et enregistré de sorte que la prochaine fois que vous voulez faire une chose similaire à vos données de test, vous pouvez facilement l'exécuter sans avoir à déterminer quelles sont les tables traitées qui nécessitent la suppression d'enregistrements.

2
HLGEM

Prenant un peu plus loin la réponse acceptée, j'avais besoin de le faire à travers des tables dans différents schémas. J'ai mis à jour le script pour inclure le schéma dans les scripts de suppression générés.

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_fitz

Extension de la réponse de croisharp pour prendre en compte les déclencheurs, c'est-à-dire une solution sensible au schéma qui désactive tous les déclencheurs affectant, supprime les lignes et active les déclencheurs.

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
2
Łukasz Nojek

Le message de Kevin est incomplet, son t-sql sp affiche uniquement la commande, pour exécuter ces commandes, avant la dernière fin, ajoutez ceci

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
2
croisharp

après avoir sélectionné, vous devez créer et exécuter la suppression réelle

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
1
dan

Postez ici un script qui fonctionnera avec des clés étrangères contenant plus d'une colonne.

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 '+@table_name+'.'+@referencing_column_name+'='+ @referencing_table_name+'.'+@referencing_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 '+@table_name+' ON '+@table_name+'.'+@referencing_column_name+'='+ @referencing_table_name+'.'+@referencing_column_name+ @criteria,
                                @referencing_table_name
                                )
                            --END
                            --ELSE
                            --BEGIN
                                --insert into @to_delete (criteria, table_name)
                                --VALUES( ' LEFT JOIN '+@table_name+' ON '+@table_name+'.'+@referencing_column_name+'='+ @referencing_table_name+'.'+@referencing_column_name,
                                --@referencing_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 '+@Where
    exec (@Sql)
    PRINT @Sql

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

Ce script a deux problèmes: 1. Vous devez indiquer la condition 1 = 1 afin de supprimer toute la base de la table. 2. Cela crée les relations directes avec la table de base uniquement. Si la table finale a une autre relation parent de table, la suppression échoue

DELETE FROM [dbo]. [Table2] WHERE TableID in (sélectionnez [ID] dans [dbo]. [Table3] où 1 = 1)

Si table2 a une relation parent table1

0
prampe