Eh bien, en général, parce que vous ne pouvez pas utiliser les fonctions d'agrégation dans la partie récursive de CTE, vous devez déplacer la partie de concaténation de colonnes vers un autre CTE. Vous aurez :
;
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