Bagaimana menemukan dependensi kunci asing di SQL Server?

163

Bagaimana saya bisa menemukan semua dependensi kunci asing pada kolom tertentu?

Apa saja alternatif yang berbeda (secara grafis dalam SSMS, kueri / tampilan dalam SQL Server, alat basis data pihak ke-3, kode dalam .NET)?

Bahkan Mien
sumber

Jawaban:

290

Permintaan berikut akan membantu Anda memulai. Ini daftar semua Hubungan Kunci Asing dalam database saat ini.

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

Anda juga dapat melihat hubungan secara grafis di dalam SQL Server Management studio dalam Database Diagram.

John Sansom
sumber
8
Terima kasih! Saya hanya perlu menambahkan << WHERE FK.TABLE_NAME = 'MyTable' AND CU.COLUMN_NAME = 'MyColumn' >> >> untuk mendapatkan kolom tertentu.
Bahkan Mien
1
+1! Dan jika diperlukan untuk mendapatkan kolom tertentu tetapi untuk semua tabel, "WHERE CU.COLUMN_NAME = 'MyColumn'" akan melakukannya.
liang
1
Mirip dengan Even - Saya menggunakan WHERE PK.TABLE_NAME = 'MyTable' untuk menemukan tabel yang diandalkan.
Lanceomagnifico
7
@samkitshah: Tidak ada yang mengatakan akan melakukannya. Pertanyaan ini ditandai dengan sql-server, yang menurut definisi adalah teknologi Microsoft. Postgres tidak ada hubungannya dengan itu.
Neolisk
2
-1: Permintaan ini melewatkan kunci asing yang didukung oleh batasan unik atau indeks unik, bukan oleh kunci primer, dalam tabel yang direferensikan. Per MSDN : “Batasan kunci asing tidak harus dihubungkan hanya dengan batasan kunci primer di tabel lain; itu juga dapat didefinisikan untuk merujuk kolom dari batasan UNIQUE di tabel lain. " Jawabannya dapat dibuat untuk bekerja dengan batasan unik dengan menghapus gabungan terakhir, dan dengan indeks unik dengan menghapus dua gabungan terakhir, tetapi itu membatasi info yang dikembalikan.
Douglas
100

mencoba: sp_help [table_name]

Anda akan mendapatkan semua informasi tentang tabel, termasuk semua kunci asing

Andrija
sumber
2
bagus, sangat berguna. Lebih berkesan daripada jawaban yang ditandai! tidak percaya Anda tidak bisa hanya melihatnya di ssms!
JonnyRaa
4
Bagus sekali, terima kasih. Tapi untuk mencari FK, saya lebih suka output dari jawaban Michael di bawah ini: sp_fkeys [table]
AjV Jsy
.... atau jika Anda tidak mendapatkan hasil dari itu (tetapi sp_help TIDAK menunjukkan kunci asing), versi yang lebih lengkap dapat membantu:sp_fkeys @fktable_name='TableName'
AjV Jsy
hebat! singkat dan ringkas!
zeroflaw
39

Jika Anda berencana menghapus atau mengganti nama tabel atau kolom hanya menemukan dependensi kunci asing mungkin tidak cukup.

Tabel referensi tidak terhubung dengan kunci asing - Anda juga harus mencari tabel referensi yang mungkin tidak terhubung dengan kunci asing (Saya telah melihat banyak database dengan desain buruk yang tidak memiliki kunci asing yang ditentukan tetapi yang memiliki data terkait ). Solusi mungkin dengan mencari nama kolom di semua tabel dan mencari kolom serupa.

Objek basis data lainnya - ini mungkin agak off topic tetapi jika Anda mencari semua referensi selain itu juga penting untuk memeriksa objek dependen.

Alat GUI - Cobalah opsi "Cari objek terkait" SSMS atau alat seperti Pencarian ApexSQL (alat gratis, diintegrasikan ke dalam SSMS) untuk mengidentifikasi semua objek bergantung termasuk tabel yang terhubung dengan kunci asing.

Timothy Walden
sumber
39

Karena pertanyaan Anda diarahkan pada satu tabel, Anda dapat menggunakan ini:

EXEC sp_fkeys 'TableName'

Saya menemukannya di SO di sini:

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

Saya menemukan informasi yang saya butuhkan dengan cepat. Ini mencantumkan tabel, kolom, dan nama kunci asing.

EDIT

Berikut tautan ke dokumentasi yang merinci berbagai parameter yang dapat digunakan: https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-fkeys-transact-sql

Michael
sumber
29

Saya pikir skrip ini lebih murah:

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
RobSiklos
sumber
6

Salah satu yang sangat saya suka gunakan disebut SQL Dependency Tracker oleh Red Gate Software . Anda bisa memasukkan objek database apa saja seperti tabel, prosedur tersimpan, dll. Dan kemudian akan secara otomatis menarik garis hubungan antara semua objek lain yang bergantung pada item yang Anda pilih.

Memberikan representasi grafis yang sangat baik dari dependensi dalam skema Anda.

TheTXI
sumber
2
Ini juga merupakan alat yang hebat untuk menunjukkan kepada orang-orang non-teknis bahwa mereka perlu mengeluarkan uang untuk refactoring desain database mereka sebelum semuanya jatuh. Grafik yang dihasilkannya cukup menarik.
Rob Allen
1
Rob: Saya suka memuat seluruh skema basis data di sana dan kemudian mengubah di antara tata letak yang berbeda supaya saya bisa melihat semua hal terbang di sekitar.
TheTXI
4

Terima kasih banyak kepada John Sansom, pertanyaannya luar biasa!

Selain itu: Anda harus menambahkan "DAN PT.ORDINAL_POSITION = CU.ORDINAL_POSITION" di akhir permintaan Anda.

Jika Anda memiliki beberapa bidang di kunci utama, pernyataan ini akan cocok dengan bidang yang sesuai satu sama lain (saya punya kasus, permintaan Anda membuat semua kombinasi, jadi untuk 2 bidang di kunci utama, saya punya 4 hasil untuk kunci asing yang sesuai) .

(Maaf saya tidak bisa mengomentari jawaban John karena saya tidak memiliki poin reputasi yang cukup).

Sierramike
sumber
3

Kueri ini akan mengembalikan detail tentang kunci asing dalam sebuah tabel, mendukung beberapa kunci kolom.

    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'
Kumait
sumber
2

Setelah pencarian panjang saya menemukan solusi yang berfungsi. Basis data saya tidak menggunakan sys.foreign_key_columns dan information_schema.key_column_usage hanya berisi kunci primer.

Saya menggunakan SQL Server 2015

SOLUSI 1 (jarang digunakan)

Jika solusi lain tidak berhasil, ini akan berfungsi dengan baik:

        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

SOLUSI 2 (umum digunakan)

Dalam sebagian besar kasus ini akan berfungsi dengan baik:

        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
profimedica
sumber
2

Anda dapat Menggunakan INFORMATION_SCHEMA.KEY_COLUMN_USAGE dan sys.foreign_key_columns untuk mendapatkan metadata kunci asing untuk tabel yaitu nama Kendala, tabel Referensi dan kolom Referensi dll.

Di bawah ini adalah kueri:

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
Shreyansh Bothra
sumber
1

Hanya sebuah catatan untuk jawaban "John Sansom",

Jika dependensi kunci asing dicari, saya pikir bahwa klausa PT Where harus:

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

dan kondisi ON -nya :

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

Seperti biasa digunakan kunci utama dari tabel asing, saya pikir masalah ini belum diperhatikan sebelumnya.

Homo Programmatoris
sumber
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

Ini akan memberi Anda:

Skema FK itu sendiri milik FK

  • "Tabel referensi" atau tabel yang memiliki FK
  • "Kolom referensi" atau kolom di dalam tabel referensi yang menunjuk ke FK
  • "Tabel yang direferensikan" atau tabel yang memiliki kolom kunci yang ditunjuk oleh FK Anda
  • "Kolom yang direferensikan" atau kolom yang merupakan kunci yang ditunjuk oleh FK Anda
Divya Agrawal
sumber
-1

GUNAKAN 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)
dave
sumber