2010-08-09 99 views
5

我必須編寫一個刪除腳本來從數據庫表中刪除行。但是表中有很多子表(外鍵),而這些子表也有子表。如何獲取數據庫表的子表的列表?

有所有關係的外鍵,我想用這個信息來獲取我必須以正確的順序(葉表首先,然後依賴關係圖)刪除的表的列表。

如何以正確的順序獲取給定表的子表列表?

回答

5

在你的數據庫上試試這個,這個腳本一次只會給你一個表的圖形。我假設你有一個Employee表,但你必須換線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 2010-08-09 21:30:52

1

對此,沒有簡單的通用答案,因爲表可以遞歸地依賴於其他表,包括自我關係等。您的結果可能不僅僅是簡單的樹。

你最好的方法應該取決於你的數據庫模型:如果你連接了樹形表,那麼先從第三個表中刪除你的數據,而不是第二個,而不是第三個。

...或禁用約束,刪除數據,啓用約束。

...或將外鍵更改爲DELETE CASCADE

這取決於你的數據模型。

+0

刪除級聯,通常是一件壞事!當兒童檔案的存在應該成爲表演停止時,可以殺死表演並刪除。 – HLGEM 2010-08-09 21:38:25

+0

完全不同意。但是,如果整個數據庫或相關表格非常小​​且「無關緊要」,它可以加速開發和測試。 – dmajkic 2010-08-10 10:49:39

1

This article給出瞭如何去做你想問的問題。

編輯:我已經修改了鏈接給原始查詢:

  1. 使腳本架構知道
  2. 正確的bug在 評論指出以下

不知道爲什麼編輯在格式化代碼塊方面做得如此糟糕。

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 2010-08-09 17:00:48

+0

對於這個問題,在查詢的末尾附加這個: 選項(maxrecursion 0)。 (默認爲允許的最大數量;如果您想將其限制爲100以外的其他值,也可以將其設置爲大於0的整數。) – 2010-08-09 19:09:49

+0

我沒有深度超過10級的葉表。這是SQL中的一個錯誤,會導致無限遞歸。 – Sylvain 2010-08-09 19:52:07

相關問題