Jak znaleźć zależności kluczy obcych w SQL Server?


163

Jak mogę znaleźć wszystkie zależności klucza obcego w określonej kolumnie?

Jakie są różne alternatywy (graficznie w SSMS, zapytania / widoki w SQL Server, narzędzia bazodanowe innych firm, kod w .NET)?

Odpowiedzi:


290

Poniższe zapytanie pomoże Ci zacząć. Zawiera listę wszystkich relacji z kluczami zagranicznymi w bieżącej bazie danych.

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

Relacje można również wyświetlać graficznie w programie SQL Server Management Studio w ramach diagramów baz danych.


8
Dzięki! Musiałem tylko dodać << WHERE FK.TABLE_NAME = 'MyTable' AND CU.COLUMN_NAME = 'MyColumn' >>, aby uzyskać określoną kolumnę.
— Nawet Mien

1
+1! W razie potrzeby, aby uzyskać określoną kolumnę, ale dla wszystkich tabel, wystarczyłoby „WHERE CU.COLUMN_NAME = 'MyColumn'”.
— liang

1
Podobnie do Even - użyłem WHERE PK.TABLE_NAME = 'MyTable', aby znaleźć tabelę, od której zależało.
— Lanceomagnifico

7
@samkitshah: Nikt nie powiedział, że tak. Pytanie jest oznaczone tagiem sql-server, który z definicji jest technologią firmy Microsoft. Postgres nie ma z tym nic wspólnego.
— Neolisk

2
-1: To zapytanie pomija klucze obce, które są wspierane przez unikalne ograniczenie lub unikalny indeks, a nie przez klucz podstawowy, w tabeli, do której się odwołuje. Według MSDN : „Ograniczenie klucza obcego nie musi być połączone tylko z ograniczeniem klucza podstawowego w innej tabeli; można go również zdefiniować w celu odniesienia do kolumn ograniczenia UNIQUE w innej tabeli. ” Odpowiedź można sprawić, aby działała z unikalnymi ograniczeniami, usuwając ostatnie sprzężenie, oraz z unikalnymi indeksami, usuwając ostatnie dwa łączenia, ale to ogranicza zwracane informacje.
— Douglas

100

próbować: sp_help [table_name]

otrzymasz wszystkie informacje o tabeli, w tym wszystkie klucze obce


2
niezły, bardzo przydatny. Bardziej zapadająca w pamięć niż zaznaczona odpowiedź! Nie mogę uwierzyć, że nie możesz ich po prostu zobaczyć w SSMS!
— JonnyRaa

4
Bardzo fajnie, dziękuję. Ale szukając FK, wolę wynik z odpowiedzi Michaela poniżej: sp_fkeys [table]
— AjV Jsy

.... lub jeśli nie uzyskasz żadnych wyników (ale sp_help WYŚWIETLA klucze obce), sp_fkeys @fktable_name='TableName'
— pełna

wspaniały! krótkie i zwięzłe!
— zeroflaw

39

Jeśli planujesz usunąć lub zmienić nazwę tabeli lub kolumny, znalezienie tylko zależności klucza obcego może nie wystarczyć.

Odwoływanie się do tabel niezwiązanych z kluczem obcym - Będziesz także musiał wyszukać tabele odwołań, które mogą nie być połączone z kluczem obcym (widziałem wiele baz danych o złym projekcie, które nie mają zdefiniowanych kluczy obcych, ale mają powiązane dane ). Rozwiązaniem może być wyszukanie nazwy kolumny we wszystkich tabelach i poszukanie podobnych kolumn.

Inne obiekty bazy danych - to prawdopodobnie trochę nie na temat, ale jeśli szukałeś wszystkich referencji, ważne jest również, aby sprawdzić zależne obiekty.

Narzędzia GUI - Wypróbuj opcję „Znajdź powiązane obiekty” programu SSMS lub narzędzia, takie jak ApexSQL Search (bezpłatne narzędzie, integruje się z SSMS), aby zidentyfikować wszystkie zależne obiekty, w tym tabele powiązane z kluczem obcym.



29

Myślę, że ten skrypt jest tańszy:

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

Ten, którego naprawdę lubię używać, nazywa się SQL Dependency Tracker firmy Red Gate Software . Możesz umieścić dowolne obiekty bazy danych, takie jak tabele, procedury składowane itp., A następnie automatycznie narysuje linie relacji między wszystkimi innymi obiektami, które opierają się na wybranych elementach.

Daje bardzo dobrą graficzną reprezentację zależności w twoim schemacie.


2
Jest to również świetne narzędzie do pokazania nietechnicznym osobom, że muszą wydać trochę pieniędzy na refaktoryzację projektu bazy danych, zanim wszystko się rozpadnie. Wykresy, które generuje, są dość atrakcyjne.
— Rob Allen

1
Rob: Lubię ładować tam cały schemat bazy danych, a następnie przełączać się między różnymi układami, aby móc obserwować, jak wszystkie rzeczy latają.
— TheTXI

4

Wielkie dzięki dla Johna Sansoma, jego zapytanie jest wspaniałe!

Ponadto: na końcu zapytania należy dodać „AND PT.ORDINAL_POSITION = CU.ORDINAL_POSITION”.

Jeśli masz wiele pól w kluczu podstawowym, ta instrukcja dopasuje do siebie odpowiednie pola (miałem przypadek, twoje zapytanie utworzyło wszystkie kombinacje, więc dla 2 pól w kluczu podstawowym miałem 4 wyniki dla odpowiedniego klucza obcego) .

(Przepraszam, że nie mogę skomentować odpowiedzi Johna, ponieważ nie mam wystarczającej liczby punktów reputacji).


3

To zapytanie zwróci szczegóły dotyczące kluczy obcych w tabeli, obsługuje wiele kluczy kolumn.

    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

Po długich poszukiwaniach znalazłem działające rozwiązanie. Moja baza danych nie używa sys.foreign_key_columns, a information_schema.key_column_usage zawiera tylko klucze podstawowe.

Używam SQL Server 2015

ROZWIĄZANIE 1 (rzadko używane)

Jeśli inne rozwiązania nie działają, to będzie działać dobrze:

        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

ROZWIĄZANIE 2 (powszechnie używane)

W większości przypadków zadziała to dobrze:

        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

Możesz użyć INFORMATION_SCHEMA.KEY_COLUMN_USAGE i sys.foreign_key_columns, aby uzyskać metadane klucza obcego dla tabeli, tj. Nazwę ograniczenia, tabelę referencyjną i kolumnę referencyjną itp.

Poniżej znajduje się zapytanie:

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

Tylko uwaga do odpowiedzi @ „John Sansom”,

Jeśli szukane są zależności klucza obcego , myślę, że klauzula PT Where powinna być:

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

i jest włączony stan:

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

Ponieważ powszechnie używany jest klucz podstawowy tabeli obcej, myślę, że ten problem nie został wcześniej zauważony.


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

To da ci:

Sam FK Schemat, do którego należy FK

  • „Tabela referencyjna” lub tabela, która ma FK
  • „Kolumna odniesienia” lub kolumna wewnątrz tabeli odwołań, która wskazuje na FK
  • „Tabela, do której istnieją odwołania” lub tabela zawierająca kolumnę kluczową, na którą wskazuje Twój FK
  • „Kolumna, do której istnieje odwołanie” lub kolumna będąca kluczem, na który wskazuje Twój FK

-1

UŻYJ schematu 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)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.