在SQL中查找交叉依赖表

时间:2013-08-12 00:56:00

标签: sql sql-server-2008 sql-server-2012

我需要列出所有依赖于彼此的表

示例

TableA与TableB具有外键关系 TableB与TableA具有外键关系

到目前为止,我得到了脚本来查找表的外键关系,但是如何过滤它们以获得交叉表引用。

我的脚本是:

SELECT  CAST(p.name AS VARCHAR(255)) AS [Primary Table] ,
            CAST(c.name AS VARCHAR(255)) AS [Foreign Table]
    FROM    sysobjects f
            INNER JOIN sysobjects c ON f.parent_obj = c.id
            INNER JOIN sysreferences r ON f.id = r.constid
            INNER JOIN sysobjects p ON r.rkeyid = p.id
            INNER  JOIN syscolumns rc ON r.rkeyid = rc.id
                                         AND r.rkey1 = rc.colid
            INNER  JOIN syscolumns fc ON r.fkeyid = fc.id
                                         AND r.fkey1 = fc.colid
            LEFT JOIN syscolumns rc2 ON r.rkeyid = rc2.id
                                        AND r.rkey2 = rc.colid
            LEFT JOIN syscolumns fc2 ON r.fkeyid = fc2.id
                                        AND r.fkey2 = fc.colid
    WHERE   f.type = 'F'
    ORDER BY CAST(p.name AS VARCHAR(255))

1 个答案:

答案 0 :(得分:0)

这个简单的select语句返回数据库中的循环直接外键引用:

IF OBJECT_ID('dbo.d') IS NOT NULL DROP TABLE dbo.d;
IF OBJECT_ID('dbo.c') IS NOT NULL DROP TABLE dbo.c;
IF OBJECT_ID('dbo.b') IS NOT NULL 
BEGIN
  ALTER TABLE dbo.a DROP CONSTRAINT [dbo.a(bid)->dbo.b(bid)];
  DROP TABLE dbo.b;
END
IF OBJECT_ID('dbo.a') IS NOT NULL DROP TABLE dbo.a;
CREATE TABLE dbo.a(aid INT PRIMARY KEY CLUSTERED, bid INT);
CREATE TABLE dbo.b(aid INT CONSTRAINT [dbo.b(aid)->dbo.a(aid)] REFERENCES dbo.a(aid), bid INT PRIMARY KEY CLUSTERED);
ALTER TABLE dbo.a ADD CONSTRAINT [dbo.a(bid)->dbo.b(bid)] FOREIGN KEY(bid) REFERENCES dbo.b(bid);
CREATE TABLE dbo.c(cid INT PRIMARY KEY CLUSTERED);
CREATE TABLE dbo.d(did INT PRIMARY KEY CLUSTERED, cid INT CONSTRAINT [dbo.d(cid)->dbo.c(cid)] REFERENCES dbo.c(cid));

SELECT * 
 FROM sys.foreign_keys fk1
 JOIN sys.foreign_keys fk2
 ON fk1.parent_object_id = fk2.referenced_object_id
 AND fk2.parent_object_id = fk1.referenced_object_id;

您可以在此处加入DMV sys.tablessys.columns,以获取表名和列名等附加信息。

要注意两件事:

  1. 您应该停止使用兼容性视图。它们用于支持为SQL 2000编写的旧脚本,不应在新开发中使用。

  2. 外键中最多可包含16列。您的脚本仅支持两个。但是,如果不需要列名,则根本不返回列名,因此根本不应加入sys.columns。

  3. 如果您只需要表格的名称,则可以通过使用此选择语句而无需额外的连接而离开:

    SELECT 
       QUOTENAME(OBJECT_SCHEMA_NAME(fk1.parent_object_id))+'.'+QUOTENAME(OBJECT_NAME(fk1.parent_object_id))+
       ' <-> '+
       QUOTENAME(OBJECT_SCHEMA_NAME(fk1.referenced_object_id))+'.'+QUOTENAME(OBJECT_NAME(fk1.referenced_object_id))
      FROM sys.foreign_keys fk1
      JOIN sys.foreign_keys fk2
      ON fk1.parent_object_id = fk2.referenced_object_id
      AND fk2.parent_object_id = fk1.referenced_object_id
      AND fk1.parent_object_id < fk1.referenced_object_id;
    

    我还在查询的WHERE子句中添加了一个附加条件,只包含一对。