1

我寫了一個查詢,找出主鍵 - 數據庫中的所有表之間的外鍵關係。這隻有當我們有外鍵物理存在時纔有效。遍歷數據庫中所有外鍵和生成路徑

請運行此查詢瞭解清楚我的問題。

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. 參數(參數標識,...)
  3. ParameterMethodMap(參數標識,放在methodID)--Composite主鍵
  4. 測試(TestId,參數標識,放在methodID ....)--Composite主鍵被用作外鍵
  5. 樣品(SampleId,TestId ....)

因此,當前查詢不考慮組合主鍵方案生成路徑。

我想生成類似的路徑。

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

這是不知何故我想合併複合主鍵。我怎樣才能做到這一點?

回答

0

好,一般是因爲你不能在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