查询使用子表查找根表到任何级别,递归CTE?

时间:2012-11-17 00:22:47

标签: sql recursion common-table-expression

我试图使用以下递归CTE查询从下到上找到表的引用表

With CTE_ALL AS
(
    SELECT
       1 as TopLevel, c.CONSTRAINT_NAME, cu.TABLE_NAME AS ReferencingTable,
           cu.COLUMN_NAME AS ReferencingColumn,ku.TABLE_NAME AS ReferencedTable,
           ku.COLUMN_NAME AS ReferencedColumn
      FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS c
     INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu
           ON cu.CONSTRAINT_NAME = c.CONSTRAINT_NAME
     INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE ku
           ON ku.CONSTRAINT_NAME = c.UNIQUE_CONSTRAINT_NAME
     where cu.TABLE_NAME = 'my table name'
Union All
    SELECT
           2 as BelowLevels, c.CONSTRAINT_NAME, cu.TABLE_NAME AS ReferencingTable,
           cu.COLUMN_NAME AS ReferencingColumn,ku.TABLE_NAME AS ReferencedTable,
           ku.COLUMN_NAME AS ReferencedColumn
      FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS c
     INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu
           ON cu.CONSTRAINT_NAME = c.CONSTRAINT_NAME
     INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE ku
           ON ku.CONSTRAINT_NAME = c.UNIQUE_CONSTRAINT_NAME
     INNER JOIN CTE_ALL CTE on CTE.ReferencedColumn = ku.COLUMN_NAME
           and CTE.ReferencedTable = ku.TABLE_NAME
)
select *
  from CTE_ALL
 where CTE_ALL.ReferencingTable = 'my table name'

错误地显示以下消息

Msg 530, Level 16, State 1, Line 1
The statement terminated. The maximum recursion 100 has been exhausted before
statement completion.

这显然意味着我的查询被狡猾地计划耗尽所有SQL资源。 微软的尽职调查阻止了这一点。 我想知道如果没有使用单个查询的while循环而没有临时表,我是否可以这样做。

我知道我的根表名和我的根列id,我也知道我的叶节点表名,虽然我不能说叶子节点列名可能是什么

我必须找到这个,因为我在运行时设计一个查询并执行它。此查询需要在运行时构造的ON子句之间的内部联接。不确定我是否理解我想要的。

1 个答案:

答案 0 :(得分:2)

经过几天的尝试和研究,我找到了一种方法来帮助自己,并且在了解递归CTE之后也更好。

对于所有可能认为有用的人

这是我可以最终确定的查询

DECLARE @REFERENCED_COLUMN VARCHAR(50) = 'MyColumn'
DECLARE @REFERENCING_TABLE VARCHAR(50) = 'MyTable'

    ;WITH
        CTE_Relationship (ReferencingTable, ReferencingColumn, ReferencedTable, ReferencedColumn) AS
        (
            SELECT
                CU.TABLE_NAME AS ReferencingTable, CU.COLUMN_NAME AS ReferencingColumn,
                KU.TABLE_NAME AS ReferencedTable, KU.COLUMN_NAME AS ReferencedColumn
            FROM
                INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
                INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CU ON CU.CONSTRAINT_NAME = C.CONSTRAINT_NAME
                INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KU ON KU.CONSTRAINT_NAME = C.UNIQUE_CONSTRAINT_NAME
        ),
        CTE_Recursive_Relationship (ReferencingTable, ReferencingColumn, ReferencedTable, ReferencedColumn, Pass) AS
        (
            SELECT
                R.ReferencingTable, R.ReferencingColumn, R.ReferencedTable, R.ReferencedColumn, 1 AS Pass
            FROM
                CTE_Relationship R
            WHERE
                R.ReferencingTable = @REFERENCING_TABLE

        UNION ALL

            SELECT
                R.ReferencingTable, R.ReferencingColumn, R.ReferencedTable, R.ReferencedColumn, RR.Pass + 1
            FROM
                CTE_Relationship R
                INNER JOIN CTE_Recursive_Relationship RR ON R.ReferencingTable = RR.ReferencedTable
                    AND R.ReferencedColumn = @REFERENCED_COLUMN
        )
        SELECT
            DISTINCT RR.*
        FROM
            CTE_Recursive_Relationship RR
        ORDER BY RR.Pass