¿Cómo encontrar dependencias de clave externa en SQL Server?


163

¿Cómo puedo encontrar todas las dependencias de clave externa en una columna en particular?

¿Cuáles son las diferentes alternativas (gráficamente en SSMS, consultas / vistas en SQL Server, herramientas de bases de datos de terceros, código en .NET)?

Respuestas:


290

La siguiente consulta le ayudará a comenzar. Enumera todas las relaciones de clave externa dentro de la base de datos actual.

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

También puede ver las relaciones gráficamente en el estudio de administración de SQL Server en Diagramas de base de datos.


8
¡Gracias! Solo necesitaba agregar << WHERE FK.TABLE_NAME = 'MyTable' AND CU.COLUMN_NAME = 'MyColumn' >> para obtener la columna específica.
Incluso Mien

1
+1! Y si es necesario para obtener la columna específica pero para todas las tablas, "WHERE CU.COLUMN_NAME = 'MyColumn'" funcionaría.
liang

1
Similar a Even: utilicé WHERE PK.TABLE_NAME = 'MyTable' para encontrar la tabla de la que dependía.
Lanceomagnifico

77
@samkitshah: Nadie dijo que lo haría. La pregunta está etiquetada como sql-server, que por definición es tecnología Microsoft. Postgres no tiene nada que ver con eso.
Neolisco

2
-1: Esta consulta pierde claves foráneas que están respaldadas por una restricción única o índice único, en lugar de por una clave primaria, en la tabla referenciada. Según MSDN : “Una restricción de clave externa no tiene que estar vinculada solo a una restricción de clave primaria en otra tabla; también se puede definir para hacer referencia a las columnas de una restricción ÚNICA en otra tabla ". Se puede hacer que la respuesta funcione con restricciones únicas eliminando la última combinación, y con índices únicos eliminando las dos últimas combinaciones, pero eso restringe la información devuelta.
Douglas

100

tratar: sp_help [table_name]

obtendrá toda la información sobre la tabla, incluidas todas las claves externas


2
Buena, muy útil. Más memorable que la respuesta marcada! ¡No puedo creer que no puedas verlos en SMS!
JonnyRaa

44
Muy bien, gracias. Pero para buscar FK, prefiero el resultado de la respuesta de Michael a continuación: sp_fkeys [table]
AjV Jsy

.... o si no obtiene resultados de eso (pero sp_help muestra claves externas), la versión más completa puede ayudar:sp_fkeys @fktable_name='TableName'
AjV Jsy

¡magnífico! breve y conciso!
zeroflaw

39

Si planea eliminar o renombrar una tabla o columna, encontrar solo dependencias de claves externas podría no ser suficiente.

Tablas de referencia que no están conectadas con clave externa : también deberá buscar tablas de referencia que no estén conectadas con clave externa (he visto muchas bases de datos con un diseño incorrecto que no tenían claves externas definidas pero que sí tenían datos relacionados ) La solución podría ser buscar el nombre de la columna en todas las tablas y buscar columnas similares.

Otros objetos de la base de datos : es probable que esto esté un poco fuera de tema, pero si estaba buscando todas las referencias, también es importante verificar los objetos dependientes.

Herramientas GUI: pruebe la opción "Buscar objetos relacionados" de SSMS o herramientas como ApexSQL Search (herramienta gratuita, se integra en SSMS) para identificar todos los objetos dependientes, incluidas las tablas conectadas con clave externa.


39

Debido a que su pregunta está dirigida a una sola tabla, puede usar esto:

EXEC sp_fkeys 'TableName'

Lo encontré en SO aquí:

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

Encontré la información que necesitaba con bastante rapidez. Enumera la tabla, la columna y el nombre de la clave externa.

EDITAR

Aquí hay un enlace a la documentación que detalla los diferentes parámetros que se pueden usar: https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-fkeys-transact-sql


29

Creo que este script es menos costoso:

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

Uno que realmente me gusta usar se llama SQL Dependency Tracker de Red Gate Software . Puede colocar cualquier objeto de la base de datos, como tablas, procedimientos almacenados, etc., y luego dibujará automáticamente las líneas de relación entre todos los otros objetos que dependen de los elementos seleccionados.

Da una muy buena representación gráfica de las dependencias en su esquema.


2
También es una gran herramienta para mostrar a las personas no técnicas que necesitan gastar algo de dinero en refactorizar el diseño de su base de datos antes de que todo se caiga. Los gráficos que genera son bastante convincentes.
Rob Allen

1
Rob: Me gusta cargar un esquema de base de datos completo allí y luego cambiar entre los diferentes diseños solo para poder ver todas las cosas volar.
TheTXI

4

Muchas gracias a John Sansom, su consulta es excelente.

Además: debe agregar "AND PT.ORDINAL_POSITION = CU.ORDINAL_POSITION" al final de su consulta.

Si tiene varios campos en la clave primaria, esta instrucción coincidirá con los campos correspondientes entre sí (tuve el caso, su consulta creó todas las combinaciones, por lo que para 2 campos en la clave primaria, obtuve 4 resultados para la clave externa correspondiente) .

(Lo siento, no puedo comentar la respuesta de John ya que no tengo suficientes puntos de reputación).


3

Esta consulta devolverá detalles sobre claves foráneas en una tabla, admite múltiples claves de columna.

    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

Después de una larga búsqueda, encontré una solución de trabajo. Mi base de datos no utiliza las columnas sys.foreign_key_columns y information_schema.key_column_usage solo contiene claves principales.

Yo uso SQL Server 2015

SOLUCIÓN 1 (raramente utilizada)

Si otras soluciones no funcionan, esto funcionará bien:

        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

SOLUCIÓN 2 (de uso común)

En la mayoría de los casos, esto funcionará bien:

        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

Puede usar INFORMATION_SCHEMA.KEY_COLUMN_USAGE y sys.foreign_key_columns para obtener los metadatos de clave externa para una tabla, es decir, nombre de restricción, tabla de referencia y columna de referencia, etc.

A continuación se muestra la 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

1

Solo una nota para la respuesta de @ "John Sansom",

Si se buscan las dependencias de clave externa , creo que la cláusula PT Where debería ser:

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

y es la condición ON :

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

Como comúnmente se usa la clave principal de la tabla externa, creo que este problema no se ha notado antes.


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

Te dará:

El propio esquema FK al que pertenece el FK

  • La "tabla de referencia" o la tabla que tiene el FK
  • La "columna de referencia" o la columna dentro de la tabla de referencia que apunta al FK
  • La "tabla referenciada" o la tabla que tiene la columna clave a la que apunta su FK
  • La "columna referenciada" o la columna que es la clave a la que apunta su FK

-1

USE información_esquema;

SELECT COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
FROM KEY_COLUMN_USAGE
WHERE (table_name = *tablename*) AND NOT (REFERENCED_TABLE_NAME IS NULL)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.