2010-08-09 12 views
5

मुझे डेटाबेस तालिका बनाने वाली पंक्तियों को हटाने के लिए एक डिलीट स्क्रिप्ट लिखनी है। हालांकि तालिका में बहुत से बच्चे टेबल (विदेशी कुंजी) हैं और उन बच्चों की टेबल में बच्चों की टेबल भी हैं।डेटाबेस तालिका के लिए बाल तालिकाओं की सूची कैसे प्राप्त करें?

सभी रिश्तों के लिए विदेशी कुंजी हैं और मैं इस जानकारी का उपयोग टेबलों की सूची प्राप्त करने के लिए करना चाहूंगा जहां मुझे सही क्रम में (पत्ते की मेज और पहले निर्भरता ग्राफ) को हटाना होगा।

मुझे सही क्रम में किसी दिए गए तालिका के लिए बाल तालिकाओं की सूची कैसे प्राप्त हो सकती है?

उत्तर

5

अपने डेटाबेस पर इसे आज़माएं, यह स्क्रिप्ट आपको एक समय में एक टेबल के लिए ग्राफ प्रदान करेगी। मुझे लगता है कि आप एक कर्मचारी तालिका है, लेकिन आप लाइन 2 अपने डेटाबेस की एक विशिष्ट तालिका जाँच करने के लिए परिवर्तन होगा:

DECLARE @masterTableName varchar(1000) 
SET @masterTableName = 'Employee' 

DECLARE @ScannedTables TABLE(Level int, Name varchar(1000) collate Latin1_General_CI_AS) 

DECLARE @currentTableCount INT 
DECLARE @previousTableCount INT 
DECLARE @level INT 

SET @currentTableCount = 0 
SET @previousTableCount = -1 
SET @level = 0 

INSERT INTO @ScannedTables VALUES (@level, @masterTableName) 

WHILE @previousTableCount <> @currentTableCount 
BEGIN 

    SET @previousTableCount = @currentTableCount 

    INSERT INTO @ScannedTables 

     SELECT DISTINCT 
      @level + 1, TC.Table_Name COLLATE Latin1_General_CI_AS 

     FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC 
     LEFT JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC ON TC.Constraint_Name = RC.Constraint_Name 
     LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FTC ON RC.Unique_Constraint_Name = FTC.Constraint_Name 

     WHERE TC.CONSTRAINT_TYPE = 'FOREIGN KEY' 

     AND FTC.TABLE_NAME COLLATE Latin1_General_CI_AS IN (SELECT Name FROM @ScannedTables WHERE Level = @level) 
     AND TC.Table_Name COLLATE Latin1_General_CI_AS NOT IN (SELECT Name FROM @ScannedTables) 

    SET @level = @level + 1 

    SELECT @currentTableCount = COUNT(*) FROM @ScannedTables 
END 

SELECT * FROM @ScannedTables 
+0

यह वही है जो मुझे चाहिए था। – Sylvain

1

इसके लिए कोई साधारण सामान्य उत्तर नहीं है, क्योंकि तालिकाएं आत्मनिर्भरता आदि सहित अन्य तालिकाओं पर निर्भर रूप से निर्भर हो सकती हैं। आपका परिणाम सरल पेड़ से अधिक हो सकता है।

आपका सबसे अच्छा तरीका आपके डीबी मॉडल पर निर्भर होना चाहिए: यदि आपके पास पेड़ तालिकाओं को जोड़ा गया है, तो तीसरे स्थान से पहले, तीसरे स्थान से पहले अपना डेटा हटाएं।

... या बाधाओं को अक्षम करें, डेटा हटाएं, बाधाओं को सक्षम करें।

... या DELETE CASCADE पर विदेशी कुंजी बदलें।

यह आपके डेटा मॉडल पर निर्भर करता है।

+0

हटाने झरना, आम तौर पर एक बुरी बात! प्रदर्शन को मार सकते हैं और हटा सकते हैं जब बाल अभिलेखों का अस्तित्व शो स्टॉपर होना चाहिए था। – HLGEM

+0

अधिक सहमत नहीं हो सका। फिर भी, यदि पूरा डेटाबेस, या संबंधित तालिका बहुत छोटी है और "महत्वहीन" है तो यह विकास और परीक्षण को तेज कर सकती है। – dmajkic

1

This article आप जो पूछ रहे हैं उसे करने का एक अच्छा विचार देता है।

संपादित करें:

  1. स्क्रिप्ट स्कीमा बारे में पता
  2. सही बग
नहीं

यकीन है कि नीचे टिप्पणी में उल्लेख किया बनाओ: मैं के लिए लिंक में दिए गए मूल प्रश्न संशोधित कर लिया है संपादक कोड ब्लॉक स्वरूपण का इतना खराब काम क्यों कर रहा है।

with Fkeys as (

    select distinct 

     OnTable  = onTableSchema.name + '.' + OnTable.name 
     ,AgainstTable = againstTableSchema.name + '.' + AgainstTable.name 

    from 

     sysforeignkeys fk 

     inner join sys.objects onTable 
      on fk.fkeyid = onTable.object_id 
     inner join sys.objects againstTable 
      on fk.rkeyid = againstTable.object_id 

     inner join sys.schemas onTableSchema 
      on onTable.schema_id = onTableSchema.schema_id 

     inner join sys.schemas againstTableSchema 
      on againstTable.schema_id = againstTableSchema.schema_id 

    where 1=1 
     AND AgainstTable.TYPE = 'U' 
     AND OnTable.TYPE = 'U' 
     -- ignore self joins; they cause an infinite recursion 
     and onTableSchema.name + '.' + OnTable.name <> againstTableSchema.name + '.' + AgainstTable.name 
    ) 

,MyData as (

    select 
     OnTable = s.name + '.' + o.name 
     ,AgainstTable = FKeys.againstTable 

    from 

     sys.objects o 
      inner join sys.schemas s 
       on o.schema_id = s.schema_id 

     left join FKeys 
      on s.name + '.' + o.name = FKeys.onTable 
     left join Fkeys fk2 
      on s.name + '.' + o.name = fk2.AgainstTable 
       and fk2.OnTable = Fkeys.AgainstTable 

    where 1=1 
     and o.type = 'U' 
     and o.name not like 'sys%' 
     and fk2.OnTable is null 
    ) 

,MyRecursion as (

    -- base case 
    select 
     TableName = OnTable 
     ,Lvl  = 1 
    from 
     MyData 
    where 1=1 
     and AgainstTable is null 

    -- recursive case 
    union all select 
     TableName = OnTable 
     ,Lvl  = r.Lvl + 1 
    from 
     MyData d 
     inner join MyRecursion r 
      on d.AgainstTable = r.TableName 
) 

select 
    Lvl = max(Lvl) 
    ,TableName 
    ,strSql = 'delete from [' + tablename + ']' 
from 
    MyRecursion 
group by 
    TableName 
order by 
    1 desc 
    ,2 desc 
+0

+1 - समाधान एक परीक्षण डेटाबेस पर काम करता है जो मैंने बनाया है। हालांकि, यह मेरे असली डेटाबेस पर काम नहीं करता है। मुझे यह त्रुटि मिलती है: कथन पूर्ण होने से पहले अधिकतम रिकर्सन 100 समाप्त हो गया है। मैंने अधिकतम रिकर्सन बढ़ाने की कोशिश की और एक ही परिणाम मिला। मुझे लगता है कि एक एज केस है जो उस कोड द्वारा कवर नहीं है और जो अनंत रिकर्सन का कारण बनता है। – Sylvain

+0

उस समस्या के लिए, क्वेरी के अंत में इसे संलग्न करें: विकल्प (maxrecursion 0)। (अधिकतम संख्या के लिए स्वीकार्य है; आप इसे एक पूर्णांक> 0 पर भी सेट कर सकते हैं यदि आप इसे 100 से कुछ अन्य चीज़ों तक सीमित करना चाहते हैं।) –

+0

मेरे पास 10 स्तरों से अधिक गहरे पत्ते की टेबल नहीं हैं। यह एसक्यूएल में एक बग है जो अनंत रिकर्सन का कारण बनता है। – Sylvain

संबंधित मुद्दे

 संबंधित मुद्दे