我必須編寫一個刪除腳本來從數據庫表中刪除行。但是表中有很多子表(外鍵),而這些子表也有子表。如何獲取數據庫表的子表的列表?
有所有關係的外鍵,我想用這個信息來獲取我必須以正確的順序(葉表首先,然後依賴關係圖)刪除的表的列表。
如何以正確的順序獲取給定表的子表列表?
我必須編寫一個刪除腳本來從數據庫表中刪除行。但是表中有很多子表(外鍵),而這些子表也有子表。如何獲取數據庫表的子表的列表?
有所有關係的外鍵,我想用這個信息來獲取我必須以正確的順序(葉表首先,然後依賴關係圖)刪除的表的列表。
如何以正確的順序獲取給定表的子表列表?
在你的數據庫上試試這個,這個腳本一次只會給你一個表的圖形。我假設你有一個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
對此,沒有簡單的通用答案,因爲表可以遞歸地依賴於其他表,包括自我關係等。您的結果可能不僅僅是簡單的樹。
你最好的方法應該取決於你的數據庫模型:如果你連接了樹形表,那麼先從第三個表中刪除你的數據,而不是第二個,而不是第三個。
...或禁用約束,刪除數據,啓用約束。
...或將外鍵更改爲DELETE CASCADE
。
這取決於你的數據模型。
This article給出瞭如何去做你想問的問題。
編輯:我已經修改了鏈接給原始查詢:
不知道爲什麼編輯在格式化代碼塊方面做得如此糟糕。
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
+1 - 該解決方案適用於我創建的測試數據庫。但是,它不適用於我的真實數據庫。我得到這個錯誤:在語句完成前,最大遞歸100已經耗盡。我試着增加最大遞歸併得到相同的結果。我想有一個邊緣案例沒有被該代碼覆蓋,並導致無限遞歸。 – Sylvain 2010-08-09 17:00:48
對於這個問題,在查詢的末尾附加這個: 選項(maxrecursion 0)。 (默認爲允許的最大數量;如果您想將其限制爲100以外的其他值,也可以將其設置爲大於0的整數。) – 2010-08-09 19:09:49
我沒有深度超過10級的葉表。這是SQL中的一個錯誤,會導致無限遞歸。 – Sylvain 2010-08-09 19:52:07
這正是我所需要的。 – Sylvain 2010-08-09 21:30:52