我使用Entity Framework从我的模型中生成我的表,并且我不时地遇到多个级联路径的问题。 e.g:
引入FOREIGN KEY约束 ' FK_dbo.SurveyorSurveys_dbo.Surveys_Survey_ID'桌子上 ' SurveyorSurveys'可能导致循环或多个级联路径。
我发现在这个新表的级联路径所在的位置非常耗时,因此我可以删除其中一个级联删除。我认为如果我可以在系统表上运行查询,向我展示所涉及的完整路径,那将非常有用。有没有人知道如何做到这一点?
例如我有这个sql:
SELECT
ro.name referenced_object,
po.name parent_object,
fk.name foreign_key
FROM sys.foreign_keys fk
INNER JOIN sys.all_objects po
ON fk.parent_object_id = po.object_id
INNER JOIN sys.all_objects ro
ON fk.referenced_object_id = ro.object_id
WHERE delete_referential_action_desc = 'CASCADE'
and (po.name = 'Surveys' or po.name = 'Surveyors'')
ORDER BY ro.name
但是这只会让我在层次结构中达到一个级别,在更高级别删除级联删除可能会更好,所以我最终调整并重新运行sql,直到我找到完整路径
答案 0 :(得分:3)
这通常与recursive query有关。
首先澄清一下sys.all_objects
中的列名:
parent_object_id
是指拥有外键的对象,因此它不是关系中的父级,而是孩子。referenced_object_id
是关系中的父母。知道了这一点,我们可以编写一个递归查询,通过将前一级别的子级与后续级别中的父级连接来收集外键关系树:
WITH [Cascades] AS(
SELECT
fk.referenced_object_id AS [RootId],
fk.parent_object_id AS [ChildId],
fk.referenced_object_id AS [ParentId],
fk.name foreign_key,
1 AS [Level]
FROM sys.foreign_keys fk
WHERE delete_referential_action_desc = 'CASCADE'
UNION ALL
SELECT [Cascades].[RootId],
fk.parent_object_id,
fk.referenced_object_id,
fk.name foreign_key,
[Cascades].[Level] + 1
FROM sys.foreign_keys fk
INNER JOIN [Cascades] ON [Cascades].[ChildId] = fk.referenced_object_id
WHERE delete_referential_action_desc = 'CASCADE'
)
SELECT [root].Name AS [Root],
po.Name AS [Parent],
co.Name AS [Child],
foreign_key,
cs.[Level]
FROM [Cascades] cs
INNER JOIN sys.all_objects [root] ON cs.[RootId] = [root].object_id
INNER JOIN sys.all_objects po ON cs.ParentId = po.object_id
INNER JOIN sys.all_objects co ON cs.ChildId = co.object_id
WHERE [root].name = 'Surveys'
ORDER BY [Root], [Parent], [Level], [Child]
如果我在简单的树级层次结构中执行查询,则输出为:
Root Parent Child foreign_key Level
-----------------------------------
A A B1 FK_B1_A 1
A A B2 FK_B2_A 1
A B1 C FK_C_B1 2
答案 1 :(得分:2)
替代sql基于Gert的优秀答案。这个允许我指定叶子并显示每行的完整级联路径
WITH Cascades
AS (SELECT
fk.parent_object_id,
fk.referenced_object_id,
fk.name foreign_keys,
CAST(ro.name + ' -> ' + po.name AS nvarchar(256)) path,
1 AS level
FROM sys.foreign_keys fk
INNER JOIN sys.all_objects po
ON fk.parent_object_id = po.object_id
INNER JOIN sys.all_objects ro
ON fk.referenced_object_id = ro.object_id
WHERE delete_referential_action_desc = 'CASCADE'
-- specifying leaf instead of root:
AND po.name IN ('Surveys', 'Surveyors', 'surveyorsurveys')
UNION ALL SELECT
fk.parent_object_id,
fk.referenced_object_id,
CAST(fk.name + ' -> ' + Cascades.foreign_keys as nvarchar(128)),
CAST(ro.name + ' -> ' + cascades.path AS nvarchar(256)),
cascades.level + 1
FROM sys.foreign_keys fk
INNER JOIN sys.all_objects po
ON fk.parent_object_id = po.object_id
INNER JOIN sys.all_objects ro
ON fk.referenced_object_id = ro.object_id
INNER JOIN cascades
ON cascades.referenced_object_id = fk.parent_object_id
WHERE delete_referential_action_desc = 'CASCADE')
SELECT
path,
foreign_keys,
level
FROM Cascades
ORDER BY path