Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Durchlaufen Sie alle Fremdschlüssel in der Datenbank und generieren Sie einen Pfad

Da Sie im Allgemeinen keine Aggregatfunktionen im rekursiven Teil des CTE verwenden können, sollten Sie den Teil der Spaltenverkettung in einen anderen CTE verschieben. Sie haben:

    ;

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