2008-09-22 11 views
32

मेरे पास ग्राहक डेटा से भरा डेटाबेस है। यह इतना बड़ा है कि यह काम करने के लिए वास्तव में बोझिल है, और मैं इसे सिर्फ 10% ग्राहकों तक सीमित कर दूंगा, जो विकास के लिए काफी है। मेरे पास बहुत सारी टेबल हैं और मैं उन्हें "डिलीट कैस्केड" के साथ बदलना नहीं चाहता, खासकर क्योंकि यह एक बार का सौदा है।SQL सर्वर 2005 में, क्या मैं अपनी टेबल पर संपत्ति सेट किए बिना कैस्केड हटा सकता हूं?

क्या मैं एक डिलीट ऑपरेशन कर सकता हूं जो पहले बिना सेट किए मेरे सभी टेबलों के माध्यम से कैस्केड करता है? यदि नहीं, तो मेरा सबसे अच्छा विकल्प क्या है?

उत्तर

52

आपकी सलाह के संयोजन और एक स्क्रिप्ट मैं ऑनलाइन पाया, मैं एक प्रक्रिया है कि एसक्यूएल आप चला सकते हैं का उत्पादन करेगा एक सोपानी ON DELETE CASCADE की परवाह किए बिना हटाने की कार्यवाही करने दिया। यह शायद समय की एक बड़ी बर्बादी थी, लेकिन मेरे पास इसे लिखने में अच्छा समय था। इस तरह से ऐसा करने का एक फायदा यह है कि आप प्रत्येक पंक्ति के बीच GO कथन डाल सकते हैं, और इसे एक बड़ा लेनदेन नहीं होना चाहिए। मूल एक पुनरावर्ती प्रक्रिया थी; यह एक स्टैक टेबल में रिकर्सन को अनलॉक करता है।

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

अच्छा स्क्रिप्ट! धन्यवाद! – splattne

+0

क्या यह स्क्रिप्ट मुझे उदाहरण के लिए 'कोड = एबीसी और नाम = डेव' – ThePower

+1

में भेजने की अनुमति देगी, लेकिन यह कुछ समय हो गया है, लेकिन मुझे ऐसा लगता है! –

2

मैं आमतौर पर उन रिकॉर्ड्स को हटाने के लिए प्रश्न लिखता हूं जिन्हें मैं नहीं चाहता हूं और इसे भविष्य के संदर्भ के लिए .sql फ़ाइल के रूप में सहेजता हूं। स्यूडोकोड है:

  1. चयन आईडी मुख्य तालिका के रिकॉर्ड है कि मैं एक अस्थायी तालिका
  2. में नष्ट करने के लिए प्रत्येक संबंधित तालिका जो अस्थायी तालिका में मिलती है के लिए एक हटाने क्वेरी लिखना चाहते हैं के।
  3. मेरी temp तालिका में शामिल होने वाली मुख्य तालिका के लिए एक डिलीट क्वेरी लिखें।
2

मेरा सुझाव आगे बढ़ना और एक स्क्रिप्ट लिखना है जो संशोधित रिश्तों की सूची निर्यात करते समय डेटाबेस में प्रत्येक संबंध में डिलीट कैस्केड को जोड़ देगा। फिर आप प्रक्रिया को उलट सकते हैं और सूची में प्रत्येक तालिका पर हटाए गए कैस्केड कमांड को हटा सकते हैं।

2

व्यक्तिगत रूप से यदि आप उत्पादन में रिकॉर्ड छोड़ने जा रहे हैं, तो मैं उन्हें विकास में भी छोड़ दूंगा। अन्यथा आप कोड लिख सकते हैं जो रिकॉर्डसेट छोटा होता है लेकिन असली रिकॉर्डसेट का सामना करते समय समय समाप्त होता है।

लेकिन यदि आप ऐसा करने के लिए दृढ़ हैं, तो मैं उन रिकॉर्ड्स के आईडी फ़ील्ड की प्रतिलिपि बनाउंगा जिन्हें आप मुख्य तालिका से पहले कार्य तालिका में अलग करना चाहते हैं। फिर मैं प्रत्येक संबंधित तालिका लेता हूं और उस वर्कटेबल में शामिल होने वाले डिलीट को केवल उन रिकॉर्ड्स को हटाने के लिए लिखता हूं। पैरेंट टेबल के साथ खत्म करो। सुनिश्चित करें कि यह ia एक स्क्रिप्ट में लिखा गया है और अगली बार जब आप अपने टेस्ट डेटा पर एक समान काम करना चाहते हैं, तो आप इसे आसानी से चला सकते हैं कि यह पता लगाने के बिना कि उन तालिकाओं को हटाया गया है जिनके लिए हटाए गए रिकॉर्ड की आवश्यकता है।

5

SQL सर्वर प्रबंधन स्टूडियो में जाएं और डेटाबेस पर राइट-क्लिक करें। कार्य का चयन करें-> स्क्रिप्ट बनाएं। दो बार अगला क्लिक करें। विकल्प विंडो पर केवल इसे CREATE कथन उत्पन्न करने के लिए सेट करें, और विदेशी कुंजी को छोड़कर सब कुछ गलत में डाल दें। अगला पर क्लिक करें। टेबल्स का चयन करें और फिर अगला क्लिक करें। "सभी का चयन करें" बटन पर क्लिक करें और अगला क्लिक करें, फिर एक क्वेरी विंडो या फ़ाइल की अपनी पसंद में स्क्रिप्ट भेजें और स्क्रिप्ट भेजें (क्लिपबोर्ड का उपयोग न करें, क्योंकि यह एक बड़ी स्क्रिप्ट हो सकती है)। अब उन सभी स्क्रिप्ट को हटा दें जो तालिका जोड़ते हैं और आपको अपनी विदेशी कुंजी बनाने के लिए एक स्क्रिप्ट के साथ छोड़ा जाना चाहिए।

उस स्क्रिप्ट की प्रति बनाएं क्योंकि यह है कि आप अपने डेटाबेस को वर्तमान स्थिति में कैसे पुनर्स्थापित करेंगे। प्रत्येक बाधा के अंत में ऑन डिलीट कैस्केड जोड़ने के लिए एक खोज का उपयोग करें और प्रतिस्थापित करें। यह आपके एफके वर्तमान में कैसे स्थापित किए गए हैं और आपको कुछ मैन्युअल संपादन करने की आवश्यकता हो सकती है, इस पर निर्भर हो सकती है।

स्क्रिप्ट पीढ़ी को दोहराएं, लेकिन इस बार इसे केवल डीआरओपी कथन उत्पन्न करने के लिए सेट किया गया है। जेनरेट की गई तालिका बूंदों को मैन्युअल रूप से निकालना सुनिश्चित करें। बूंदों को चलाएं, फिर अपने संपादित किए गए क्रिएटिव को हटाएं ताकि उन्हें हटाए जाने पर सभी कैस्केड कर सकें। अपने हटाए गए, ड्रॉप स्क्रिप्ट को फिर से चलाएं और फिर उस स्क्रिप्ट को चलाएं जिसे आपने शुरुआत में सहेजा था।

इसके अलावा - अपने डीबी के पहले बैकअप बनाएं! भले ही यह सिर्फ एक dev डेटाबेस है, यदि स्क्रिप्ट का हिस्सा बिल्कुल सही नहीं है तो यह आपको कुछ सिरदर्द बचाएगा।

आशा है कि इससे मदद मिलती है!

बीटीडब्ल्यू - आपको निश्चित रूप से अपने पूर्ण परीक्षण डेटा के साथ कुछ परीक्षण करना चाहिए क्योंकि एक अन्य पोस्टर सुझाया गया है, लेकिन मैं देख सकता हूं कि आपको प्रारंभिक विकास के लिए क्यों आवश्यकता नहीं है। बस कुछ बिंदु पर क्यूए के हिस्से के रूप में शामिल करना न भूलें।

7

जब तक आप क्रिस द्वारा प्रस्तावित सभी संबंधित प्रश्नों को बनाए रखना नहीं चाहते हैं, तो ऑन डिलीट कैस्केड अब तक का सबसे तेज़ और सबसे प्रत्यक्ष समाधान है। और यदि आप इसे स्थायी किया जा नहीं करना चाहते हैं, तुम क्यों कि चालू और बंद मूल Tbl_A_MyFK बाधा (ON बिना यहाँ की तरह

  1. हटाएं इस विकल्प को स्विच होगा कुछ T-SQL कोड नहीं है CASCADE)

    ALTER TABLE Tbl_A DROP CONSTRAINT Tbl_A_MyFK

  2. पर साथ बाधा Tbl_A_MyFK सेट हटाएं CASCADE

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

  3. यहाँ आप अपने बाधा आपके हटाने

    DELETE FROM Tbl_A WHERE ...

  4. ड्रॉप कर सकते हैं Tbl_A_MyFK

    ALTER TABLE Tbl_A DROP CONSTRAINT Tbl_A_MyFK

  5. बाधा Tbl_A_MyFK सेट पर बिना DELETE CASCADE

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

1

के बाद का चयन आप का निर्माण और वास्तविक

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

बढ़ाने के लिए इसे चुनें कथन के बाद इसे जोड़ें – dan

2

थोड़ा आगे स्वीकार किए जाते हैं जवाब ले रहा है को नष्ट निष्पादित करने के लिए है, मैं अलग स्कीमा में टेबल भर में यह करने के लिए की जरूरत थी। मैंने आउटपुट हटाए गए स्क्रिप्ट में स्कीमा को शामिल करने के लिए स्क्रिप्ट को अपडेट किया है।

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

केविन पोस्ट अधूरा है, उसकी टी-एसक्यूएल एसपी केवल आदेश प्रिंट, यहाँ कम आबादी के लिए अनुकूलित स्वीकार किए जाते हैं जवाब का एक संस्करण है, इन आदेश पर अमल करने से पहले अंतिम अंत इस

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

जोड़ने डेटा मॉडल यह हटाने की सूची में जोड़ने से पहले एफके श्रृंखला में डेटा के अस्तित्व की जांच करता है।मैं परीक्षण डेटा को साफ करने के लिए इसका उपयोग करता हूं।

सक्रिय लेनदेन डीबी में इसका उपयोग न करें- यह ताले के रास्ते को बहुत लंबा रखेगा।

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

croisharp के जवाब का विस्तार है, यानी स्कीमा अवगत समाधान है कि सभी को प्रभावित करने वाले चलाता अक्षम कर देता है, पंक्तियों को हटा देता है, और ट्रिगर सक्षम बनाता है को ध्यान में चलाता लेने के लिए। 1. आप हालत का संकेत चाहिए 1 = 1 सभी तालिका आधार हटाने के लिए आपको:

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

यह स्क्रिप्ट दो मुद्दे हैं। 2. यह केवल आधार तालिका के साथ सीधा संबंध बनाता है। अंतिम तालिका एक और तालिका माता पिता संबंध नहीं हैं, तो हटाएं

[dbo] से हटाएँ असफल। [table2] कहां में TableID (चयन [ID] [dbo] से। [table3] जहां 1 = 1)

यदि तालिका 2 में अभिभावक संबंध तालिका है

1

यहां एक स्क्रिप्ट पोस्ट करें जो विदेशी कुंजी के साथ काम करेगी, एक से अधिक स्तंभ होते हैं।

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 
संबंधित मुद्दे