2008-09-22 20 views
32

Tôi có một cơ sở dữ liệu đầy đủ dữ liệu khách hàng. Nó quá lớn đến mức nó thực sự cồng kềnh để hoạt động, và tôi chỉ muốn giảm xuống còn 10% khách hàng, điều đó rất nhiều cho sự phát triển. Tôi có rất nhiều bảng và tôi không muốn thay đổi tất cả chúng bằng "ON DELETE CASCADE", đặc biệt vì đây là giao dịch một lần.Trong SQL Server 2005, tôi có thể thực hiện xóa bỏ tầng mà không cần thiết lập thuộc tính trên các bảng của tôi không?

Tôi có thể thực hiện thao tác xóa xếp chồng qua tất cả các bảng của tôi mà không cần thiết lập chúng trước không? Nếu không, lựa chọn tốt nhất của tôi là gì?

Trả lời

52

Kết hợp lời khuyên của bạn và một kịch bản tôi thấy trên mạng, tôi đã thực hiện một thủ tục mà sẽ tạo ra SQL bạn có thể chạy để thực hiện một cascaded xóa bất kể ON DELETE CASCADE. Nó có lẽ là một sự lãng phí thời gian, nhưng tôi đã có một thời gian tốt để viết nó. Một lợi thế của việc làm theo cách này là, bạn có thể đặt một tuyên bố GO giữa mỗi dòng, và nó không phải là một giao dịch lớn. Bản gốc là một thủ tục đệ quy; điều này unrolls đệ quy vào một bảng stack.

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

Kịch bản hay! Cảm ơn bạn! – splattne

+0

kịch bản này sẽ cho phép tôi gửi trong ví dụ 'code = ABC AND name = dave' – ThePower

+1

Đã một thời gian, nhưng tôi nghĩ vậy! –

2

Tôi thường chỉ viết tay các truy vấn để xóa các bản ghi mà tôi không muốn và lưu nó dưới dạng tệp .sql để tham khảo trong tương lai. Các giả là:

  1. chọn id của bản ghi từ bảng chính mà tôi muốn xóa vào một bảng temp
  2. viết một truy vấn xóa cho mỗi bảng có liên quan mà tham gia vào bảng temp.
  3. viết truy vấn xóa cho bảng chính tham gia bảng tạm thời của tôi.
2

Đề xuất của tôi là tiếp tục và viết một tập lệnh sẽ thêm dòng xóa vào mỗi mối quan hệ trong cơ sở dữ liệu trong khi xuất danh sách các mối quan hệ đã sửa đổi. Sau đó, bạn có thể đảo ngược quá trình và loại bỏ lệnh xóa tầng trên xóa trên mỗi bảng trong danh sách.

2

Cá nhân nếu bạn định lưu hồ sơ vào sản xuất, tôi cũng sẽ để chúng phát triển. Nếu không, bạn có thể viết mã hoạt động tốt khi recordset nhỏ nhưng hết thời gian khi đối mặt với recordset thực.

Nhưng nếu bạn quyết tâm làm điều này, tôi sẽ sao chép trường id của các bản ghi mà bạn muốn thoát ra khỏi bảng chính trước tiên đến bảng làm việc. Sau đó, tôi sẽ lấy mỗi bảng liên quan và viết một xóa tham gia vào đó bàn làm việc để chỉ xóa những hồ sơ. Kết thúc với bảng cha. Hãy chắc chắn rằng ia này được viết trong một kịch bản và được lưu để lần sau bạn muốn thực hiện một điều tương tự với dữ liệu thử nghiệm của mình, bạn có thể dễ dàng chạy nó mà không cần phải tìm ra các bảng bị đánh cắp nào cần bản ghi đã xóa từ chúng.

5

Đi vào SQL Server Management Studio và nhấp chuột phải vào cơ sở dữ liệu. Chọn Tác vụ-> Tạo tập lệnh. Nhấn Next hai lần. Trên cửa sổ Tùy chọn, hãy chọn thiết lập để tạo ra các câu lệnh CREATE và đặt mọi thứ thành Sai trừ các Khóa Ngoại. Bấm tiếp. Chọn Tables và nhấn Next lần nữa. Nhấp vào nút "Chọn tất cả" và nhấp vào Tiếp theo sau đó Hoàn tất và gửi tập lệnh cho bạn lựa chọn cửa sổ truy vấn hoặc tệp (không sử dụng khay nhớ tạm vì nó có thể là tập lệnh lớn). Bây giờ, hãy xóa tất cả tập lệnh để thêm các bảng và bạn nên để lại tập lệnh để tạo các khóa ngoại.

Tạo bản sao của tập lệnh đó vì đó là cách bạn sẽ khôi phục cơ sở dữ liệu về trạng thái hiện tại của nó. Sử dụng tìm kiếm và thay thế để thêm ON DELETE CASCADE vào cuối mỗi ràng buộc. Điều này có thể khác nhau tùy thuộc vào cách FK của bạn hiện được thiết lập và bạn có thể cần thực hiện một số chỉnh sửa thủ công.

Lặp lại quá trình tạo tập lệnh, nhưng lần này thiết lập để tạo các lệnh DROP. Đảm bảo xóa các giọt bảng được tạo theo cách thủ công. Chạy các giọt, sau đó chạy các chỉnh sửa đã chỉnh sửa của bạn để làm cho tất cả chúng đều bị xóa khi xóa. Thực hiện xóa của bạn, chạy lại tập lệnh thả và sau đó chạy tập lệnh mà bạn đã lưu lúc khởi động.

Đồng thời - ĐẶT LẠI DB CỦA BẠN ĐẦU TIÊN! Ngay cả khi nó chỉ là một cơ sở dữ liệu dev, nó sẽ giúp bạn tiết kiệm một số nhức đầu nếu một phần của kịch bản là không hoàn toàn đúng.

Hy vọng điều này sẽ hữu ích!

BTW - bạn chắc chắn nên làm một số thử nghiệm với dữ liệu thử nghiệm đầy đủ của bạn như một áp phích khác được đề xuất, nhưng tôi có thể thấy lý do tại sao bạn có thể không cần điều đó để phát triển ban đầu. Chỉ cần không quên bao gồm đó như là một phần của QA tại một số điểm.

7

Trừ khi bạn muốn duy trì tất cả các truy vấn liên quan như đề xuất của Chris, BẬT DELETE CASCADE là giải pháp trực tiếp nhanh nhất và nhanh nhất. Và nếu bạn không muốn nó là vĩnh viễn, tại sao bạn không có một số mã T-SQL mà sẽ chuyển sang tùy chọn này và tắt như đây

  1. Tháo gốc Tbl_A_MyFK hạn chế (không có ON DELETE CASCADE)

    ALTER TABLE Tbl_A DROP CONSTRAINT Tbl_A_MyFK

  2. thiết lập các hạn chế Tbl_A_MyFK với ON DELETE CASCADE

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

  3. Ở đây bạn có thể làm bạn xóa

    DELETE FROM Tbl_A WHERE ...

  4. thả hạn chế của bạn Tbl_A_MyFK

    ALTER TABLE Tbl_A DROP CONSTRAINT Tbl_A_MyFK

  5. thiết lập các hạn chế Tbl_A_MyFK mà không ON DELETE CASCADE

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

1

sau khi chọn bạn phải xây dựng và thực hiện thực tế xóa

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

thêm điều này sau khi chọn câu lệnh – dan

2

Lấy trả lời chấp nhận một chút nữa, tôi đã có sự cần thiết phải làm điều này qua bảng trong lược đồ khác nhau. Tôi đã cập nhật tập lệnh để bao gồm lược đồ trong các tập lệnh xóa đã xuất.

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 bài không đầy đủ, t-sql mình sp chỉ in lệnh, để thực hiện các lệnh, trước khi kết thúc cuối cùng thêm này

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

Dưới đây là một phiên bản của câu trả lời chấp nhận được tối ưu hóa cho dân cư thưa thớt mô hình dữ liệu. Nó kiểm tra sự tồn tại của dữ liệu trong một chuỗi FK trước khi thêm nó vào danh sách xóa.Tôi sử dụng nó để làm sạch dữ liệu thử nghiệm.

Không sử dụng nó trong một giao dịch hoạt động db- nó sẽ giữ khóa quá lâu.

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

Mở rộng câu trả lời của croisharp để kích hoạt xem xét, tức là giải pháp nhận biết lược đồ vô hiệu hóa tất cả ảnh hưởng đến trình kích hoạt, xóa hàng và kích hoạt trình kích hoạt.

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

kịch bản này có hai vấn đề: 1. Bạn phải ghi rõ điều kiện 1 = 1 để xóa tất cả các cơ sở bảng. 2. Điều này tạo ra các mối quan hệ trực tiếp với bảng cơ sở. Nếu bảng cuối cùng có một mối quan hệ cha mẹ khác, thì việc xóa không thành công

DELETE FROM [dbo]. [Table2] WHERE TableID in (select [ID] from [dbo]. [Table3] where 1 = 1)

Nếu bảng 2 có bảng quan hệ cha mẹ1

1

Đăng tại đây tập lệnh sẽ hoạt động với khóa ngoài chứa nhiều hơn một cột.

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 
Các vấn đề liên quan