如何在SQL Server中查找外键依赖项?


163

如何找到特定列上的所有外键依赖项?

有哪些不同的选择(在SSMS中为图形,在SQL Server中为查询/视图,第三方数据库工具,.NET中为代码)?

Answers:


290

以下查询将帮助您入门。它列出了当前数据库中的所有外键关系。

SELECT
    FK_Table = FK.TABLE_NAME,
    FK_Column = CU.COLUMN_NAME,
    PK_Table = PK.TABLE_NAME,
    PK_Column = PT.COLUMN_NAME,
    Constraint_Name = C.CONSTRAINT_NAME
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

您还可以在数据库图的SQL Server Management Studio中以图形方式查看关系。


8
谢谢!我只需要添加<< WHERE FK.TABLE_NAME ='MyTable'和CU.COLUMN_NAME ='MyColumn'>>以获取特定列。
甚至Mien

1
+1!并且,如果需要获取特定列而不是所有表,则可以执行“ WHERE CU.COLUMN_NAME ='MyColumn'”。
2013年

1
与Even相似-我使用WHERE PK.TABLE_NAME ='MyTable'查找依赖的表。
Lanceomagnifico

7
@samkitshah:没人说会。问题被标记为sql-server,根据定义,它是Microsoft技术。Postgres与它无关。
Neolisk

2
-1:此查询会丢失在引用表中由唯一约束或唯一索引而不是主键支持的外键。根据MSDN:“外键约束不必仅链接到另一个表中的主键约束;也可以定义为引用另一个表中UNIQUE约束的列。” 通过删除最后一个联接,可以使答案具有唯一性约束,而通过删除最后两个联接,可以使答案具有唯一性索引,但这会限制返回的信息。
道格拉斯

100

尝试: sp_help [table_name]

您将获得有关表的所有信息,包括所有外键


2
不错,非常有用。比标记答案更令人难忘!不敢相信你不能只看到他们在短信!
JonnyRaa 2014年

4
很好,谢谢。但是对于寻找FK,我更喜欢下面迈克尔的回答: sp_fkeys [table]
AjV Jsy 2015年

....或如果没有得到任何结果(但是sp_help确实显示外键),则较完整的版本可能会有所帮助:sp_fkeys @fktable_name='TableName'
AjV Jsy

高超!简明扼要!
zeroflaw '18

39

如果计划删除或重命名表或列,则仅查找外键依赖项可能不够。

引用未与外键连接的表 -您还需要搜索可能未与外键连接的引用表(我已经看到许多设计不良的数据库,其中未定义外键,但确实具有相关数据)。解决方案可能是在所有表中搜索列名,然后查找相似的列。

其他数据库对象 –这可能是一个话题,但如果要查找所有引用,那么检查依赖对象也很重要。

GUI工具–尝试使用SSMS的“查找相关对象”选项或ApexSQL Search之类的工具(免费工具,集成到SSMS中)来识别所有相关对象,包括与外键连接的表。



29

我认为此脚本更便宜:

SELECT f.name AS ForeignKey, OBJECT_NAME(f.parent_object_id) AS TableName,
    COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName,
    OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
    COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id

6

我真的很喜欢使用的一种叫做Red Gate Software的 SQL Dependency Tracker 。您可以放入任何数据库对象,例如表,存储过程等,然后它将自动在依赖于所选项目的所有其他对象之间绘制关系线。

很好地图形化表示了模式中的依赖关系。


2
这也是向非技术人员展示他们需要花一些钱才能重构数据库设计之前的好工具。它生成的图形非常引人注目。
罗布·艾伦,2009年

1
Rob:我喜欢在其中加载整个数据库架构,然后在不同的布局之间进行更改,这样我就可以观察所有事物。
TheTXI

4

非常感谢John Sansom,他的询问真是太好了!

另外:您应该在查询末尾添加“ AND PT.ORDINAL_POSITION = CU.ORDINAL_POSITION”。

如果主键中有多个字段,则该语句将使相应的字段彼此匹配(我有这种情况,您的查询确实创建了所有组合,因此对于主键中的2个字段,对应的外键有4个结果) 。

(抱歉,我没有足够的声誉积分,所以我无法评论约翰的回答)。


3

该查询将返回有关表中外键的详细信息,它支持多个列键。

    SELECT *
    FROM
    (
    SELECT 
    T1.constraint_name ConstraintName,
    T2.COLUMN_NAME ColumnName,
    T3.TABLE_NAME RefTableName, 
    T3.COLUMN_NAME RefColumnName,
    T1.MATCH_OPTION MatchOption, 
    T1.UPDATE_RULE UpdateRule, 
    T1.DELETE_RULE DeleteRule
    FROM 
    INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS T1
    INNER JOIN
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE T2 
    ON T1.CONSTRAINT_NAME = T2.CONSTRAINT_NAME
    INNER JOIN
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE T3 
    ON T1.UNIQUE_CONSTRAINT_NAME = T3.CONSTRAINT_NAME 
    AND T2.ORDINAL_POSITION = T3.ORDINAL_POSITION) A
    WHERE A.ConstraintName = 'table_name'

2

经过长时间的搜索,我找到了一个可行的解决方案。我的数据库不使用sys.foreign_key_columns,并且information_schema.key_column_usage仅包含主键。

我使用SQL Server 2015

解决方案1(很少使用)

如果其他解决方案不起作用,则可以正常工作:

        WITH CTE AS
        (
            SELECT 
                TAB.schema_id,
                TAB.name,
                COL.name AS COLNAME,
                COl.is_identity
            FROM 
                sys.tables TAB INNER JOIN sys.columns COL 
                    ON TAB.object_id = COL.object_id
        )
        SELECT 
            DB_NAME() AS [Database], 
            SCHEMA_NAME(Child.schema_id) AS 'Schema',
            Child.name AS 'ChildTable',
            Child.COLNAME AS 'ChildColumn',
            Parent.name AS 'ParentTable',
            Parent.COLNAME AS 'ParentColumn'
        FROM 
            cte Child INNER JOIN CTE Parent
                ON 
                    Child.COLNAME=Parent.COLNAME AND 
                    Child.name<>Parent.name AND 
                    Child.is_identity+1=Parent.is_identity

解决方案2(常用)

在大多数情况下,这可以正常工作:

        SELECT
            DB_NAME() AS [Database], 
            SCHEMA_NAME(fk.schema_id) AS 'Schema',
            fk.name 'Name',
            tp.name 'ParentTable',
            cp.name 'ParentColumn',
            cp.column_id,
            tr.name 'ChildTable',
            cr.name 'ChildColumn',
            cr.column_id
        FROM
            sys.foreign_keys fk
        INNER JOIN
            sys.tables tp ON fk.parent_object_id = tp.object_id
        INNER JOIN
            sys.tables tr ON fk.referenced_object_id = tr.object_id
        INNER JOIN
            sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
        INNER JOIN
            sys.columns cp ON fkc.parent_column_id = cp.column_id AND fkc.parent_object_id = cp.object_id
        INNER JOIN
            sys.columns cr ON fkc.referenced_column_id = cr.column_id AND fkc.referenced_object_id = cr.object_id
        WHERE 
            -- CONCAT(SCHEMA_NAME(fk.schema_id), '.', tp.name, '.', cp.name) LIKE '%my_table_name%' OR
            -- CONCAT(SCHEMA_NAME(fk.schema_id), '.', tr.name, '.', cr.name) LIKE '%my_table_name%' 
        ORDER BY
            tp.name, cp.column_id

2

您可以使用INFORMATION_SCHEMA.KEY_COLUMN_USAGE和sys.foreign_key_columns来获取表的外键元数据,例如约束名称,引用表和引用列等。

下面是查询:

SELECT  CONSTRAINT_NAME, COLUMN_NAME, ParentTableName, RefTableName,RefColName FROM 
    (SELECT CONSTRAINT_NAME,COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = '<tableName>') constraint_details
    INNER JOIN  
    (SELECT ParentTableName, RefTableName,name ,COL_NAME(fc.referenced_object_id,fc.referenced_column_id) RefColName  FROM (SELECT object_name(parent_object_id) ParentTableName,object_name(referenced_object_id) RefTableName,name,OBJECT_ID  FROM sys.foreign_keys WHERE parent_object_id = object_id('<tableName>') ) f 
    INNER JOIN   
    sys.foreign_key_columns AS fc  ON  f.OBJECT_ID = fc.constraint_object_id ) foreign_key_detail 
    on foreign_key_detail.name = constraint_details.CONSTRAINT_NAME

1

只是对@“ John Sansom”答案的注释,

如果寻求外键依赖性,我认为PT Where子句应为:

i1.CONSTRAINT_TYPE = 'FOREIGN KEY'  -- instead of 'PRIMARY KEY'

及其开启条件:

ON PT.TABLE_NAME = FK.TABLE_NAME  instead of PK.TABLE_NAME

由于通常使用外表的主键,因此我认为这个问题以前没有注意到。


0
SELECT  obj.name AS FK_NAME,
    sch.name AS [schema_name],
    tab1.name AS [table],
    col1.name AS [column],
    tab2.name AS [referenced_table],
    col2.name AS [referenced_column]
FROM sys.foreign_key_columns fkc
INNER JOIN sys.objects obj
    ON obj.object_id = fkc.constraint_object_id
INNER JOIN sys.tables tab1
    ON tab1.object_id = fkc.parent_object_id
INNER JOIN sys.schemas sch
    ON tab1.schema_id = sch.schema_id
INNER JOIN sys.columns col1
    ON col1.column_id = parent_column_id AND col1.object_id = tab1.object_id
INNER JOIN sys.tables tab2
    ON tab2.object_id = fkc.referenced_object_id
INNER JOIN sys.columns col2
    ON col2.column_id = referenced_column_id AND col2.object_id = tab2.object_id

它会给你:

FK所属的FK本身架构

  • “引用表”或具有FK的表
  • “引用列”或引用表中指向FK的列
  • FK指向的“被引用表”或具有键列的表
  • FK指向的“被引用的列”或作为键的列

-1

USE information_schema;

SELECT COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
FROM KEY_COLUMN_USAGE
WHERE (table_name = *tablename*) AND NOT (REFERENCED_TABLE_NAME IS NULL)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.