Como encontrar dependências de chave estrangeira no SQL Server?

163

Como posso encontrar todas as dependências de chave estrangeira em uma coluna específica?

Quais são as diferentes alternativas (graficamente no SSMS, consultas / visualizações no SQL Server, ferramentas de banco de dados de terceiros, código no .NET)?

Even Mien
fonte

Respostas:

290

A consulta a seguir ajudará você a começar. Ele lista todos os relacionamentos de chave estrangeira no banco de dados atual.

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

Você também pode exibir relacionamentos graficamente no SQL Server Management studio em Diagramas de banco de dados.

John Sansom
fonte
8
Obrigado! Eu só precisava adicionar << WHERE FK.TABLE_NAME = 'MyTable' AND CU.COLUMN_NAME = 'MyColumn' >> >> para obter a coluna específica.
Mesmo Mien
1
+1! E, se necessário, para obter a coluna específica, mas para todas as tabelas, "WHERE CU.COLUMN_NAME = 'MyColumn'" serviria.
liang
1
Semelhante ao Even - usei WHERE PK.TABLE_NAME = 'MyTable' para encontrar a tabela na qual dependia.
Lanceomagnifico 13/03
7
@samkitshah: Ninguém disse que sim. A pergunta está marcada como sql-server, que por definição é a tecnologia da Microsoft. O Postgres não tem nada a ver com isso.
Neolisk
2
-1: essa consulta perde chaves estrangeiras que são apoiadas por uma restrição ou índice exclusivo, e não por uma chave primária, na tabela referenciada. Por MSDN : “Uma restrição de chave estrangeira não precisa ser vinculada apenas a uma restrição de chave primária em outra tabela; também pode ser definido para referenciar as colunas de uma restrição UNIQUE em outra tabela. ” A resposta pode ser feita para trabalhar com restrições exclusivas, removendo a última associação e com índices exclusivos, removendo as duas últimas associações, mas isso restringe as informações retornadas.
Douglas
100

experimentar: sp_help [table_name]

você obterá todas as informações sobre a tabela, incluindo todas as chaves estrangeiras

Andrija
fonte
2
legal, muito útil. Mais memorável do que a resposta marcada! Não posso acreditar que você não pode vê-los em ssms!
JonnyRaa
4
Muito bom, obrigado. Mas, ao procurar por FK, prefiro a saída da resposta de Michael abaixo: sp_fkeys [table]
AjV Jsy 8/15/15
.... ou se você não obtiver resultados disso (mas o sp_help mostra chaves estrangeiras), a versão completa pode ajudar:sp_fkeys @fktable_name='TableName'
AjV Jsy 11/11/2015
excelente! breve e conciso!
21418 zeroflaw
39

Se você planeja excluir ou renomear uma tabela ou coluna, localizando apenas dependências de chave estrangeira pode não ser suficiente.

Tabelas de referência não conectadas à chave estrangeira - Você também precisará procurar tabelas de referência que podem não estar conectadas à chave estrangeira (eu já vi muitos bancos de dados com design incorreto que não tinham chaves estrangeiras definidas, mas que tinham dados relacionados ) A solução pode ser procurar o nome da coluna em todas as tabelas e procurar colunas semelhantes.

Outros objetos de banco de dados - este provavelmente é um tópico pouco interessante, mas se você estava procurando todas as referências, também é importante verificar se há objetos dependentes.

Ferramentas da GUI - Experimente a opção “Encontrar objetos relacionados” do SSMS ou ferramentas como ApexSQL Search (ferramenta gratuita, integra-se ao SSMS) para identificar todos os objetos dependentes, incluindo tabelas conectadas com chave estrangeira.

Timothy Walden
fonte
39

Como sua pergunta é voltada para uma única tabela, você pode usar o seguinte:

EXEC sp_fkeys 'TableName'

Encontrei no SO aqui:

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

Encontrei as informações necessárias rapidamente. Ele lista a tabela, a coluna e o nome da chave estrangeira.

EDITAR

Aqui está um link para a documentação que detalha os diferentes parâmetros que podem ser usados: https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-fkeys-transact-sql

Michael
fonte
29

Eu acho que esse script é mais barato:

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
fonte
6

Um que eu realmente gosto de usar é chamado SQL Dependency Tracker da Red Gate Software . Você pode colocar qualquer objeto (s) de banco de dados, como tabelas, procedimentos armazenados, etc., e ele desenhará automaticamente as linhas de relacionamento entre todos os outros objetos que dependem dos itens selecionados.

Dá uma representação gráfica muito boa das dependências no seu esquema.

TheTXI
fonte
2
Também é uma ótima ferramenta para mostrar às pessoas não técnicas que elas precisam gastar algum dinheiro na refatoração do design do banco de dados antes que tudo caia. Os gráficos gerados são bastante atraentes.
Rob Allen
1
Rob: Eu gosto de carregar um esquema de banco de dados inteiro lá e depois mudar entre os diferentes layouts, para que eu possa ver tudo o que acontece.
TheTXI
4

Muito obrigado a John Sansom, sua pergunta é fantástica!

Além disso: você deve adicionar "AND PT.ORDINAL_POSITION = CU.ORDINAL_POSITION" no final da sua consulta.

Se você tiver vários campos na chave primária, essa instrução corresponderá aos campos correspondentes (eu tive o caso, sua consulta criou todas as combinações; portanto, para 2 campos na chave primária, obtive 4 resultados para a chave estrangeira correspondente) .

(Desculpe, não posso comentar a resposta de John, pois não tenho pontos de reputação suficientes).

Sierramike
fonte
3

Esta consulta retornará detalhes sobre chaves estrangeiras em uma tabela, suporta várias chaves de coluna.

    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
fonte
2

Após uma longa pesquisa, encontrei uma solução funcional. Meu banco de dados não usa os sys.foreign_key_columns e o information_schema.key_column_usage contém apenas chaves primárias.

Eu uso o SQL Server 2015

SOLUÇÃO 1 (raramente usada)

Se outras soluções não funcionarem, isso funcionará bem:

        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

SOLUÇÃO 2 (comumente usada)

Na maioria dos casos, isso funcionará perfeitamente:

        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
fonte
2

Você pode usar o arquivo INFORMATION_SCHEMA.KEY_COLUMN_USAGE e sys.foreign_key_columns para obter os metadados da chave estrangeira de uma tabela, como nome da restrição, tabela de referência e coluna de referência, etc.

Abaixo está a consulta:

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
fonte
1

Apenas uma nota para a resposta "John Sansom",

Se as dependências de chave estrangeira forem procuradas, acho que a cláusula PT Where deve ser:

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

e é a condição ON :

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

Como normalmente é usada a chave primária da tabela estrangeira, acho que esse problema não foi percebido antes.

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

Isso lhe dará:

O próprio FK Esquema ao qual o FK pertence

  • A "tabela de referência" ou a tabela que possui o FK
  • A "coluna de referência" ou a coluna dentro da tabela de referência que aponta para o FK
  • A "tabela referenciada" ou a tabela que possui a coluna-chave para a qual o seu FK está apontando
  • A "coluna referenciada" ou a coluna que é a chave para a qual o seu FK está apontando
Divya Agrawal
fonte
-1

USE 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
fonte