【问题标题】:Traverse through all foreign keys in database and generate a path遍历数据库中的所有外键并生成路径
【发布时间】:2012-11-16 08:45:03
【问题描述】:

我写了一个查询来找出数据库中所有表之间的主键-外键关系。这只有在我们物理上存在外键时才有效。

请运行此查询以清楚地了解我的问题。

WITH 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
        , rc.name AS PrimaryKeyColumnName
        --, fk.parent_object_id AS ForeignKeyTableId
        , OBJECT_NAME(fk.parent_object_id) AS ForeignKeyTableName
        --, fkc.parent_column_id AS ForeignKeyColumnId
        , lc.name AS ForeignKeyColumnName
    FROM sys.foreign_key_columns fkc
    INNER JOIN sys.columns rc 
        ON  rc.OBJECT_ID = fkc.referenced_object_id 
        AND fkc.referenced_column_id = rc.column_id
    INNER JOIN sys.foreign_keys fk 
        ON  fk.OBJECT_ID = fkc.constraint_object_id
    INNER JOIN sys.columns lc 
        ON  lc.OBJECT_ID = fk.parent_object_id
        AND fkc.parent_column_id = lc.column_id
)
, cte2(create_date, modify_date, ConstraintName
        , PrimaryKeyTableName, PrimaryKeyColumnName
        , ForeignKeyTableName, ForeignKeyColumnName
        , Hops, path ) AS 
    (
        SELECT
            create_date, modify_date, ConstraintName
            , PrimaryKeyTableName, PrimaryKeyColumnName
            , ForeignKeyTableName, ForeignKeyColumnName 
            , 1 , CAST(QUOTENAME(PrimaryKeyTableName + '.' + PrimaryKeyColumnName) AS VARCHAR(4000))
        FROM cte
    UNION ALL
        SELECT 
            cte.create_date, cte.modify_date, cte.ConstraintName
            , cte.PrimaryKeyTableName, cte.PrimaryKeyColumnName
            , cte.ForeignKeyTableName, cte.ForeignKeyColumnName
            , cte2.Hops +1, CAST(cte2.path + '-> ' +QUOTENAME(cte.PrimaryKeyTableName+ '.' + cte.PrimaryKeyColumnName) AS VARCHAR(4000))
        FROM cte2 INNER JOIN cte ON cte2.ForeignKeyTableName = cte.PrimaryKeyTableName
        AND cte2.ForeignKeyColumnName != cte.PrimaryKeyColumnName
    )
SELECT 
ConstraintName
        , PrimaryKeyTableName, PrimaryKeyColumnName
        , ForeignKeyTableName, ForeignKeyColumnName
        , Hops, path + '-> ' + QUOTENAME(ForeignKeyTableName + '.' + ForeignKeyColumnName) AS Path
FROM cte2

除非我们在数据库中存在复合主键,否则上述查询工作顺利。

假设我有一张桌子

  1. 方法(MethodId, ....)
  2. 参数(ParameterId, ...)
  3. ParameterMethodMap(ParameterId, MethodId) --复合主键
  4. Test(TestId, ParameterId, MethodId....) --复合主键被用作外键
  5. 样本(SampleId, TestId....)

因此,考虑到复合主键场景,当前查询不会生成路径。

我想生成类似的路径。

[Method.MethodId] -> [ParameterMethodMap.MethodId, ParameterMethodMap.ParameterId] -> [Test.TestId] -> [Sample.SampleId]

这就是我想合并复合主键的原因。我该怎么做?

【问题讨论】:

    标签: sql sql-server sql-server-2008 sql-server-2005 common-table-expression


    【解决方案1】:

    嗯,一般来说,因为您不能在 CTE 的递归部分中使用聚合函数,您应该将列连接部分移到另一个 CTE。您将拥有:

        ;
    
    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-19
      • 1970-01-01
      • 2012-10-09
      • 2015-04-19
      • 1970-01-01
      • 2019-06-03
      相关资源
      最近更新 更多