Nói chung, vì bạn không thể sử dụng các hàm tổng hợp trong phần đệ quy của CTE, bạn nên chuyển phần nối cột sang một CTE khác. Bạn sẽ có:
;
WITH CTE_FKCols
AS (
SELECT FK.NAME
,'[' + STUFF((
SELECT ','
,object_name(Col.object_id) + '.' + col.NAME
FROM sys.foreign_key_columns C
INNER JOIN sys.columns Col ON Col.object_id = c.referenced_object_id
AND col.column_id = c.referenced_column_id
WHERE C.constraint_object_id = FK.object_id
FOR XML PATH('')
), 1, 1, '') + ']' Cols
FROM sys.foreign_keys FK
)
,CTE
AS (
SELECT fk.create_date
,fk.modify_date
,fkc.constraint_object_id AS ConstraintId
,OBJECT_NAME(fkc.constraint_object_id) AS ConstraintName
--, fkc.referenced_object_id AS PrimaryKeyTableId
,OBJECT_NAME(fkc.referenced_object_id) AS PrimaryKeyTableName
--, fkc.referenced_column_id AS PrimaryKeyColumnId
,OBJECT_NAME(fk.parent_object_id) AS ForeignKeyTableName
FROM sys.foreign_key_columns fkc
INNER JOIN sys.foreign_keys fk ON fk.OBJECT_ID = fkc.constraint_object_id
)
,cte2 (
create_date
,modify_date
,ConstraintName
,PrimaryKeyTableName
,ForeignKeyTableName
,Hops
,path
)
AS (
SELECT create_date
,modify_date
,ConstraintName
,PrimaryKeyTableName
,ForeignKeyTableName
,1
,CAST((
SELECT F.Cols
FROM CTE_FKCols F
WHERE F.NAME = cte.ConstraintName
) AS NVARCHAR(4000))
FROM cte
UNION ALL
SELECT cte.create_date
,cte.modify_date
,cte.ConstraintName
,cte.PrimaryKeyTableName
,cte.ForeignKeyTableName
,cte2.Hops + 1
,CAST((
cte2.path + CAST('-> ' AS NVARCHAR(4000)) + (
SELECT F.Cols
FROM CTE_FKCols F
WHERE F.NAME = cte.ConstraintName
)
) AS NVARCHAR(4000))
FROM cte2
INNER JOIN cte ON cte2.ForeignKeyTableName = cte.PrimaryKeyTableName
AND cte2.PrimaryKeyTableName != cte.PrimaryKeyTableName --Remove self-reference
)
SELECT *
FROM cte2