How to find foreign key dependencies in SQL Server?
如何在特定列上找到所有外键依赖项?
有哪些不同的替代方案(图形化在SSMS中,SQL Server中的查询/视图,第三方数据库工具,.NET中的代码)?
以下查询将帮助您入门。它列出了当前数据库中的所有外键关系。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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 |
您还可以在Database Diagrams中的SQL Server Management Studio中以图形方式查看关系。
尝试:
您将获得有关表的所有信息,包括所有外键
因为您的问题是针对单个表,您可以使用:
1 | 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
如果您计划删除或重命名表或列,则仅查找外键依赖项可能不够。
引用未与外键连接的表 - 您还需要搜索可能未与外键连接的引用表(我看过许多设计不良的数据库没有定义外键但确实有相关数据)。解决方案可能是在所有表中搜索列名并查找类似的列。
其他数据库对象 - 这可能有点偏离主题,但如果您正在寻找所有引用,那么检查依赖对象也很重要。
GUI工具 - 尝试SSMS"查找相关对象"选项或工具,如ApexSQL搜索(免费工具,集成到SSMS中),以识别所有依赖对象,包括与外键连接的表。
我认为这个脚本比较便宜:
1 2 3 4 5 6 7 | 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 |
我真正喜欢使用的是Red Gate Software的SQL Dependency Tracker。您可以放入任何数据库对象(如表,存储过程等),然后它将自动绘制依赖于所选项的所有其他对象之间的关系线。
为您的架构中的依赖项提供了非常好的图形表示。
非常感谢John Sansom,他的查询非常棒!
另外:您应该在查询结尾添加"AND PT.ORDINAL_POSITION = CU.ORDINAL_POSITION"。
如果主键中有多个字段,则此语句将相互匹配相应的字段(我遇到过这种情况,您的查询确实创建了所有组合,因此对于主键中的2个字段,我有4个相应外键的结果) 。
(对不起,我不能评论John的答案,因为我没有足够的声望点)。
此查询将返回表中外键的详细信息,它支持多个列键。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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' |
您可以使用INFORMATION_SCHEMA.KEY_COLUMN_USAGE和sys.foreign_key_columns来获取表的外键元数据,即约束名称,引用表和引用列等。
以下是查询:
1 2 3 4 5 6 7 | 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 |
经过长时间的搜索,我找到了一个可行
我的数据库不使用sys.foreign_key_columns,而information_schema.key_column_usage只包含主键。
我使用SQL Server 2015
解决方案1(很少使用)
如果其他解决方案不起作用,这将正常工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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(常用)
在大多数情况下,这将工作得很好:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 |
只是@"John Sansom"回答的注释,
如果寻求外键依赖,我认为PT Where子句应该是:
1 | i1.CONSTRAINT_TYPE = 'FOREIGN KEY' -- instead of 'PRIMARY KEY' |
及其ON条件:
1 | ON PT.TABLE_NAME = FK.TABLE_NAME – instead of PK.TABLE_NAME |
由于通常使用外表的主键,我认为这个问题以前没有被注意到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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指向的键的列
USE information_schema;
1 2 3 | SELECT COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM KEY_COLUMN_USAGE WHERE (table_name = *tablename*) AND NOT (REFERENCED_TABLE_NAME IS NULL) |