【问题标题】:How to find foreign key dependencies in SQL Server?如何在 SQL Server 中查找外键依赖项?
【发布时间】:2010-10-29 20:54:32
【问题描述】:

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

有哪些不同的替代方案(SSMS 中的图形、SQL Server 中的查询/视图、第 3 方数据库工具、.NET 中的代码)?

【问题讨论】:

    标签: .net sql-server foreign-keys


    【解决方案1】:

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

    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 中以图形方式查看关系。

    【讨论】:

    • 谢谢!我只需要添加 > 来获取特定的列。
    • +1!如果需要获取特定列但对于所有表,“WHERE CU.COLUMN_NAME = 'MyColumn'”就可以了。
    • 类似于 Even - 我使用 WHERE PK.TABLE_NAME = 'MyTable' 来查找所依赖的表。
    • @samkitshah:没有人说会。该问题被标记为 sql-server,根据定义,它是 Microsoft 技术。 Postgres 与它无关。
    • -1:此查询遗漏了引用表中由唯一约束或唯一索引而不是主键支持的外键。每MSDN:“外键约束不必只链接到另一个表中的主键约束;它也可以定义为引用另一个表中唯一约束的列。”答案可以通过删除最后一个连接来处理唯一约束,并通过删除最后两个连接来处理唯一索引,但这会限制返回的信息。
    【解决方案2】:

    试试:sp_help [table_name]

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

    【讨论】:

    • 不错,非常有用。比标记的答案更令人难忘!不敢相信你不能只在 ssms 中看到它们!
    • 非常好,谢谢。但是为了寻找 FK,我更喜欢下面迈克尔回答的输出:sp_fkeys [table]
    • .... 或者如果你没有得到任何结果(但 sp_help 确实显示外键),更完整的版本可能会有所帮助:sp_fkeys @fktable_name='TableName'
    • 太棒了!简洁明了!
    【解决方案3】:

    因为您的问题是针对单个表格的,您可以使用这个:

    EXEC sp_fkeys 'TableName'
    

    我在这里找到了它:

    https://stackoverflow.com/a/12956348/652519

    我很快就找到了我需要的信息。它列出了外键的表、列和名称。

    编辑

    这里是详细说明可以使用的不同参数的文档的链接:https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-fkeys-transact-sql

    【讨论】:

      【解决方案4】:

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

      引用未与外键连接的表 - 您还需要搜索可能未与外键连接的引用表(我见过许多设计不佳的数据库没有定义了外键,但确实有相关数据)。解决方案可能是在所有表中搜索列名并查找相似的列。

      其他数据库对象——这可能有点跑题了,但如果您要查找所有引用,那么检查依赖对象也很重要。

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

      【讨论】:

        【解决方案5】:

        我觉得这个脚本比较便宜:

        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。您可以放入任何数据库对象,例如表、存储过程等,然后它会自动绘制依赖于您所选项目的所有其他对象之间的关系线。

          为您的架构中的依赖关系提供非常好的图形表示。

          【讨论】:

          • 这也是一个很好的工具,可以向非技术人员展示他们需要花一些钱来重构他们的数据库设计,以免一切崩溃。它生成的图表非常引人注目。
          • Rob:我喜欢在其中加载整个数据库模式,然后在不同的布局之间切换,这样我就可以看到所有的东西飞来飞去。
          【解决方案7】:

          非常感谢 John Sansom,他的提问非常棒!

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

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

          (抱歉,我没有足够的声望点,无法评论约翰的回答)。

          【讨论】:

            【解决方案8】:

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

                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'
            

            【讨论】:

              【解决方案9】:

              经过长时间的搜索,我找到了一个可行的解决方案。 我的数据库不使用 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
              

              【讨论】:

                【解决方案10】:

                您可以使用 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
                

                【讨论】:

                  【解决方案11】:

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

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

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

                  及其ON条件:

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

                  由于常用外表的主键,我想这个问题以前没有注意到。

                  【讨论】:

                    【解决方案12】:
                    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所属的Schema

                    • “参考表”或具有 FK 的表
                    • “引用列”或引用表中指向 FK 的列
                    • “引用表”或具有 FK 指向的键列的表
                    • “引用列”或 FK 指向的键的列

                    【讨论】:

                      【解决方案13】:

                      使用信息模式;

                      SELECT COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
                      FROM KEY_COLUMN_USAGE
                      WHERE (table_name = *tablename*) AND NOT (REFERENCED_TABLE_NAME IS NULL)
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2014-03-27
                        • 2011-11-28
                        • 2012-10-21
                        • 2011-02-03
                        • 2010-09-22
                        • 2011-11-30
                        • 2021-01-05
                        • 2018-02-23
                        相关资源
                        最近更新 更多