Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Percorra todas as chaves estrangeiras no banco de dados e gere um caminho


Bem, em geral porque você não pode usar funções agregadas na parte recursiva do CTE, você deve mover a parte de concatenação de colunas para outro CTE. Voce terá:
    ;

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