Sql 如何修复递归CTE以基于sys.foreign\u键建立表依赖关系?
递归CTE以层次结构格式为嵌套依赖项生成重复结果。我希望有一个字段,它可以列出每个选项的路径 我尝试过用自上而下和自下而上的方法重写这条语句,但我无法消除实际上不存在的依赖关系。 例如,如果我有基A、子B和孙子C,我想要A、A\B和A\B\C-但不是A\CSql 如何修复递归CTE以基于sys.foreign\u键建立表依赖关系?,sql,sql-server,common-table-expression,Sql,Sql Server,Common Table Expression,递归CTE以层次结构格式为嵌套依赖项生成重复结果。我希望有一个字段,它可以列出每个选项的路径 我尝试过用自上而下和自下而上的方法重写这条语句,但我无法消除实际上不存在的依赖关系。 例如,如果我有基A、子B和孙子C,我想要A、A\B和A\B\C-但不是A\C WITH rCTE ( [Level], -- Dimension count [RootSchema], -- Child table db schema [RootID], -- Child table ID, s
WITH rCTE
(
[Level], -- Dimension count
[RootSchema], -- Child table db schema
[RootID], -- Child table ID, sys.foreign_keys.parent_object_ID
[RTableName], -- Name of the child table
[ParentSchema], -- Parent table db schema
[ParentID], -- Parent table IDsys.foreign_keys.referenced_object_ID
[PTableName], -- Name of the parent table
[Path] -- The path to the item
) AS (
SELECT
1 as [Level],
object_schema_name(f.parent_object_id),
f.parent_object_id as [RootID],
object_name(f.parent_object_id) as [RTableName],
OBJECT_SCHEMA_NAME(f.referenced_object_ID),
CONVERT(int,null) as [ParentID],
object_name(referenced_object_id) as [PTableName],
CONVERT(varchar(150),object_name(f.referenced_object_id) --+ '\' + ISNULL(object_name(f.parent_object_id),'') -- Troubleshooting
) as [Path]
FROM
sys.foreign_keys f join sys.tables t on t.object_id = f.parent_object_id
--WHERE NOT EXISTS
--( Select 1
-- from sys.foreign_keys ff
-- where f.parent_object_id = ff.referenced_object_id
--)
UNION ALL
SELECT
[Level]+1,
object_schema_name(f.parent_object_id),
f.parent_object_id,
object_name(f.parent_object_id),
OBJECT_SCHEMA_NAME(f.referenced_object_ID),
f.referenced_object_id
,object_name(f.referenced_object_id)
,CAST(r.[Path] + '\' + r.[RTableName] as varchar(150))
from sys.foreign_keys f join rCTE r on f.referenced_object_id = r.rootID
--where f.parent_object_id <> r.ParentID
)
select distinct x.[level] -- change
--,r.ParentSchema
,r.[PTableName]
,r.[RTableName]
,r.[Path]
from rCTE r join
(
select
[ptableName], max([Level]) as [Level]
from rCTE
GROUP BY [pTableName]
) x on x.pTableName = r.pTableName
ORDER BY [Path]
--select distinct * from rcte
我参考了很多网站,但这是最好的一个,这张从那里拍摄的照片展示了我所说的道路。
在收到Kris Wenzel邮件列表中的一封电子邮件后,我联系了我最初在问题中链接的博客的Kris Wenzel,该邮件建议向他发送您遇到的挑战。他能够为提出的问题提供一个解决方案,我在下面介绍了这个问题。这将为仅基于数据库中外键的层次结构制定一种自底向上的方法
;
WITH cte_FKtable(Parent
, FKConstraintName
, Child)
AS (SELECT PO.name AS ParentTable
, FK.name
, RO.name AS ChildTable
FROM sys.foreign_keys AS FK
INNER JOIN sys.objects AS RO ON RO.object_id = FK.referenced_object_id
INNER JOIN sys.objects AS PO ON PO.object_id = FK.parent_object_id),
cte_allTable(parent
, FKConstraintName
, child)
AS (SELECT Parent
, FKConstraintName
, Child
FROM cte_FKtable
UNION
SELECT O.name
, NULL
, NULL
FROM sys.objects AS O
WHERE type = 'U' AND -- user table
NOT EXISTS
(
SELECT 1
FROM cte_FKtable
WHERE( cte_FKtable.parent = o.name OR
cte_FKtable.child = o.name
)
)),
cte_tree(name
, description
, level
, sort)
AS (SELECT DISTINCT
parent
, CAST(parent AS varchar(1024))
, 1
, CAST(parent AS varchar(1024))
FROM cte_allTable AS a
WHERE a.parent NOT IN
(
SELECT child
FROM cte_allTable
WHERE child IS NOT NULL
) OR
a.child IS NULL
UNION ALL
SELECT FK.child
, CAST(REPLICATE('|---', cte_tree.level) + FK.child AS varchar(1024))
, cte_tree.level + 1
, CAST(cte_tree.sort + '\' + FK.child AS varchar(1024))
FROM cte_tree
INNER JOIN cte_FKtable AS FK ON cte_tree.name = FK.parent)
SELECT DISTINCT
name
, description
, level
, sort
FROM cte_tree
ORDER BY sort;
但是你想做什么呢?正是我说的-我希望能够基于外键依赖性详细说明层次结构。因此,如果我有一个基表、一个派生表和一个依赖于派生表的第三个表,我希望将base\derived\dependent显示为路径变量。最终的目标是将它与另一个脚本结合使用,这样,如果根据提供的数据,它决定在表3中启用一个位标志,然后,我可以跟踪表3路径区域中的依赖项,同时禁用派生表和基表。我能想到的唯一其他解决方案是使用类似的方法,然后基于依赖列动态迭代,生成链接,如我在主帖中链接的示例中所示,在两步。也许这是最好的办法?