Как найти зависимости внешнего ключа в SQL Server?


163

Как я могу найти все зависимости внешнего ключа для определенного столбца?

Какие есть альтернативы (графически в SSMS, запросы / представления в SQL Server, сторонние инструменты для баз данных, код в .NET)?

Ответы:


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' AND CU.COLUMN_NAME = 'MyColumn' >>, чтобы получить конкретный столбец.
Даже Mien

1
+1! И если необходимо получить конкретный столбец, но для всех таблиц, подойдет «WHERE CU.COLUMN_NAME = 'MyColumn'».
Лян

1
Аналогично Even - я использовал WHERE PK.TABLE_NAME = 'MyTable', чтобы найти таблицу, от которой зависела.
Lanceomagnifico

7
@ samkitshah: Никто не говорил, что будет. Вопрос помечен sql-сервером, который по определению является технологией Microsoft. Postgres не имеет к этому никакого отношения.
Неолиск

2
-1: этот запрос пропускает внешние ключи, которые поддерживаются уникальным ограничением или уникальным индексом, а не первичным ключом в ссылочной таблице. Согласно MSDN : «Ограничение внешнего ключа не обязательно должно быть связано только с ограничением первичного ключа в другой таблице; его также можно определить для ссылки на столбцы ограничения UNIQUE в другой таблице ». Ответ может быть сделан для работы с уникальными ограничениями, удалив последнее соединение, и с уникальными индексами, удалив последние два соединения, но это ограничивает возвращаемую информацию.
Дуглас

100

пытаться: sp_help [table_name]

вы получите всю информацию о таблице, включая все внешние ключи


2
хороший, очень полезный. Более запоминающимся, чем отмеченный ответ! не могу поверить, что вы не можете просто увидеть их в ssms!
JonnyRaa

4
Очень мило спасибо. Но для поиска ФК я предпочитаю вывод из ответа Майкла ниже: sp_fkeys [table]
AjV Jsy

.... или если вы не получите никаких результатов (но sp_help показывает внешние ключи), более полная версия может помочь:sp_fkeys @fktable_name='TableName'
AjV Jsy

великолепно! кратко и лаконично!
Zeroflaw

39

Если вы планируете удалить или переименовать таблицу или столбец, то может быть недостаточно найти только зависимости внешнего ключа.

Ссылки на таблицы, не связанные с внешним ключом. Вам также нужно будет найти ссылки на таблицы, которые могут быть не связаны с внешним ключом (я видел много баз данных с плохим дизайном, в которых не определены внешние ключи, но в которых есть связанные данные. ). Решением может быть поиск имени столбца во всех таблицах и поиск похожих столбцов.

Другие объекты базы данных - это, вероятно, немного не по теме, но если вы искали все ссылки, важно также проверить наличие зависимых объектов.

Инструменты с графическим интерфейсом. Попробуйте опцию «Найти связанные объекты» в SSMS или инструменты, такие как ApexSQL Search (бесплатный инструмент, интегрируется в SSMS), чтобы идентифицировать все зависимые объекты, включая таблицы, связанные с внешним ключом.


39

Поскольку ваш вопрос ориентирован на одну таблицу, вы можете использовать это:

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


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 Dependency Tracker от Red Gate Software . Вы можете добавить любой объект (ы) базы данных, такие как таблицы, хранимые процедуры и т. Д., И тогда он автоматически проведет линии связи между всеми другими объектами, которые зависят от выбранных вами элементов.

Дает очень хорошее графическое представление зависимостей в вашей схеме.


2
Это также отличный инструмент для того, чтобы показать нетехническим людям, что им нужно потратить немного денег на рефакторинг своей базы данных, прежде чем все рухнет. Графики, которые он генерирует, довольно убедительны.
Роб Аллен

1
Роб: Мне нравится загружать всю схему базы данных, а затем переключаться между различными макетами, чтобы я мог наблюдать за тем, как все вокруг летает.
TheTXI

4

Большое спасибо Джону Сэнсому, его запрос потрясающий!

Кроме того: вы должны добавить «И 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'

3

После долгих поисков я нашел рабочее решение. Моя база данных не использует 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

Просто записка для @ "Джона Сэнсома",

Если ищутся зависимости внешнего ключа , я думаю, что предложение 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

-1

ИСПОЛЬЗОВАНИЕ 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)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.