开发者社区> 问答> 正文

在SQL Server 2005中,是否可以在不设置表属性的情况下进行级联删除?

我有一个充满客户数据的数据库。它是如此之大,以至于操作起来确实很麻烦,我只希望将其缩减至10%的客户,这对开发来说是很大的。我有很多桌子,我不想用“ ON DELETE CASCADE”更改它们,特别是因为这是一次性交易。

我可以执行删除所有表的删除操作而无需先设置它们吗?如果没有,我最好的选择是什么?

展开
收起
心有灵_夕 2019-12-29 00:16:42 1120 0
1 条回答
写回答
取消 提交回答
  • 这是针对稀疏填充的数据模型而优化的已接受答案的版本。在将数据添加到删除列表之前,它将检查FK链中是否存在数据。我用它来清理测试数据。

    不要在活动的事务数据库中使用它-它会将锁保持太长时间。

    /*
    -- ============================================================================
    -- 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
    
    2019-12-29 00:17:16
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
SQL Server 2017 立即下载
GeoMesa on Spark SQL 立即下载
原生SQL on Hadoop引擎- Apache HAWQ 2.x最新技术解密malili 立即下载