Як знайти залежності від зовнішніх ключів у 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 в межах діаграм баз даних.


8
Дякую! Мені просто потрібно було додати << WHERE FK.TABLE_NAME = "MyTable" AND CU.COLUMN_NAME = "MyColumn" >>, щоб отримати конкретний стовпець.
Навіть Мієн

1
+1! І якщо потрібно, щоб отримати конкретний стовпець, але для всіх таблиць, "WHERE CU.COLUMN_NAME =" MyColumn "" зробить.
laang

1
Подібно до Even - я використовував WHERE PK.TABLE_NAME = 'MyTable', щоб знайти таблицю, від якої залежав.
Lanceomagnifico

7
@samkitshah: Ніхто не сказав, що це буде. Питання позначено тегом sql-сервера, який за визначенням є технологією Microsoft. Постгрес тут ні до чого.
Неоліск

2
-1: Цей запит пропускає іноземні ключі, які підкріплені унікальним обмеженням або унікальним індексом, а не первинним ключем у посиланій таблиці. За MSDN : "Обмеження зовнішнього ключа не повинно бути пов'язане лише з обмеженням первинного ключа в іншій таблиці; його також можна визначити для посилання на стовпці обмеження UNIQUE в іншій таблиці ». Відповідь можна зробити так, щоб працювати з унікальними обмеженнями, видаляючи останнє з'єднання, та з унікальними індексами, видаляючи останні два об'єднання, але це обмежує повернуту інформацію.
Дуглас

100

спробуйте: sp_help [table_name]

ви отримаєте всю інформацію про таблицю, включаючи всі зовнішні ключі


2
приємний, дуже корисний. Пам’ятніше, ніж помічена відповідь! не можу повірити, що ти не можеш просто побачити їх у смс!
JonnyRaa

4
Дуже приємно, дякую. Але для пошуку ФК я вважаю за краще висновок з відповіді Майкла нижче: sp_fkeys [table]
AjV Jsy

.... або якщо ви не отримаєте результатів з цього (але sp_help НЕ показує сторонні ключі), більш повна версія може допомогти:sp_fkeys @fktable_name='TableName'
AjV Jsy

чудово! короткий і стислий!
zeroflaw

39

Якщо ви плануєте видалити або перейменувати таблицю або стовпець, знаходження лише залежностей від зовнішнього ключа може бути недостатньо.

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

Інші об'єкти бази даних - це, мабуть, трохи поза темою, але якщо ви шукали всі посилання, то важливо також перевірити наявність залежних об'єктів.

Інструменти графічного інтерфейсу - спробуйте параметр SSS "Знайти пов'язані об'єкти" або такі інструменти, як ApexSQL Search (безкоштовний інструмент, інтегрується в SSMS), щоб визначити всі залежні об'єкти, включаючи таблиці, підключені із зовнішнім ключем.


39

Оскільки ваше запитання орієнтоване на єдину таблицю, ви можете використовувати це:

EXEC sp_fkeys 'TableName'

Я знайшов його на SO тут:

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

Я знайшов потрібну мені інформацію досить швидко. У ньому перераховані таблиця, стовпець та назва іноземного ключа.

EDIT

Ось посилання на документацію, в якій детально описані різні параметри, які можна використовувати: 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

Мені дуже подобається використовувати SQL Deckerpender Tracker від Red Gate Software . Ви можете розмістити будь-які об'єкти бази даних, такі як таблиці, збережені процедури тощо. Це автоматично автоматично намалює лінії взаємозв'язку між усіма іншими об'єктами, які покладаються на вибрані вами елементи.

Дає дуже хороше графічне зображення залежностей у вашій схемі.


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

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

4

Велике спасибі Джону Сансому, його запит приголомшливий!

Крім того: в кінці запиту слід додати "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_column, а інформація_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_col column, щоб отримати метадані зовнішнього ключа для таблиці, тобто імені обмеження, таблиці посилань та стовпчика Reference тощо.

Нижче наведено запит:

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 :

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

ВИКОРИСТОВУЄТЬ інформацію_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.