SQL-Server查询自身的结果

时间:2013-02-04 12:25:24

标签: sql-server tsql loops

我正在尝试识别从数据库中删除表格的风险。

数据库很大,包含数百个表。

我有一个返回与表关联的外键的查询。所以我可以提供我想要删除的表名,它告诉我哪些表依赖于它拥有的列。所以我还必须删除返回的表。

我的问题是,因为我需要删除这些表,我希望看到任何其他表依赖于初始结果。

因此我相信我需要我的查询来循环调用自己的最后一次运行的结果,直到没有更多的独特结果。

这可能吗?有没有更简单的方法呢?

编辑:这是查询:

SELECT
      PK.TABLE_NAME AS PrimaryTable,
      FK.TABLE_NAME AS ForeignTable,
      PT.COLUMN_NAME AS PrimaryColumn,
      CU.COLUMN_NAME AS ForeignColumn,
      C.CONSTRAINT_NAME AS ConstraintName
FROM
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN (
                  SELECT i1.TABLE_NAME, i2.COLUMN_NAME
                  FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
                  INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
                  WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
                  ) PT ON PT.TABLE_NAME = PK.TABLE_NAME
WHERE PK.TABLE_NAME IN
('Table1','Table2')
ORDER BY
1,2,3,4

3 个答案:

答案 0 :(得分:2)

您可以尝试使用CTE。我发现在最终的select语句中编写实际的where子句更容易,但如果性能是个问题,我建议你在relations CTE (在UNION ALL上面)上写where子句

CTE选择声明

;WITH q AS (
  SELECT
        PK.TABLE_NAME AS PrimaryTable,
        FK.TABLE_NAME AS ForeignTable,
        PT.COLUMN_NAME AS PrimaryColumn,
        CU.COLUMN_NAME AS ForeignColumn,
        C.CONSTRAINT_NAME AS ConstraintName
  FROM
  INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
  INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
  INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
  INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
  INNER JOIN (
                    SELECT i1.TABLE_NAME, i2.COLUMN_NAME
                    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
                    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
                    WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
                    ) PT ON PT.TABLE_NAME = PK.TABLE_NAME
)
, Relations AS (
  SELECT  PrimaryTable AS Root
          , *
  FROM    q
  UNION ALL
  SELECT  r.Root
          , q.PrimaryTable
          , q.ForeignTable
          , q.PrimaryColumn
          , q.ForeignColumn
          , q.ConstraintName
  FROM    q
          INNER JOIN Relations r ON r.ForeignTable = q.PrimaryTable
)
SELECT  *
FROM    Relations
WHERE   Root IN ('Table1','Table2')
ORDER BY
1,2,3,4

答案 1 :(得分:0)

我想你可以创建一个全局临时表,其中包含表名和已处理标志的字段,并添加初始表名。使用要删除的表的初始种子调用代码。将结果插入临时表。然后迭代临时表中的值,将结果添加到临时表中,确保不会在完成时插入重复项并将每个重复项标记为已处理。继续,直到处理表中的每个记录。

答案 2 :(得分:0)

尝试这样的事情......

DECLARE @tablename varchar
DECLARE @flag bit
SET @tablename = 'some_table_name'
SET @flag-1
WHILE EXISTS(SELECT PK.TABLE_NAME AS PrimaryTable,
  FK.TABLE_NAME AS ForeignTable,
  PT.COLUMN_NAME AS PrimaryColumn,
  CU.COLUMN_NAME AS ForeignColumn . . . where PK.TABLE_NAME = @tablename)
  begin
   SET @flag=0
   SET @tablename=<assign the tables with fk referred by primarykey tables>
  end
IF(@flag=1)
 <delete query>

它只是一个想法来解决你的场景而不是完整的解决方案。