Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Query to find out if foreign key is referenced anywhere else in the database

I have table Animal.

I want to return everything from this table + one column which denotes if record is referenced anywhere else as a foreign key.

I.E.:

Animal_Id    Name  
    1        Cat
    2        Dog
    3        Parrot

I want to return this:

AnimalId    Name     Referenced 
    1        Cat         true
    2        Dog         false
    3        Parrot      true

by 'referenced' I mean if a specific Animal_Id was referenced in any other table in the database as a foreign key. I think I first can query information_schema and find out what tables contain this foreign key and then use loop and dynamic sql to execute
select count(*) from eachTable where AnimalID = 1

Does anyone have a snippet on how to do that?

like image 911
user194076 Avatar asked Mar 08 '12 23:03

user194076


People also ask

How do I find foreign key references in SQL?

Using SQL Server Management Studio Open the Table Designer for the table containing the foreign key you want to view, right-click in the Table Designer, and choose Relationships from the shortcut menu. In the Foreign Key Relationships dialog box, select the relationship with properties you want to view.

How find all foreign key references to column in SQL Server?

The most Simplest one is by using sys. foreign_keys_columns in SQL. Here the table contains the Object ids of all the foreign keys wrt their Referenced column ID Referenced Table ID as well as the Referencing Columns and Tables.


1 Answers

This should do it:

SELECT OO.Animal_ID, OO.Name, CASE WHEN XX.REFERENCED IS NULL THEN 'false' ELSE 'true' END Referenced
FROM   Animal OO
       OUTER APPLY (SELECT SUM(1) REFERENCED
                    FROM   (SELECT FkAnimal_ID FROM AnimalRef1 RR WHERE RR.FkAnimal_ID = OO.Animal_ID UNION ALL
                            SELECT FkAnimal_ID FROM AnimalRef2 RR WHERE RR.FkAnimal_ID = OO.Animal_ID UNION ALL
                            SELECT FkAnimal_ID FROM AnimalRef3 RR WHERE RR.FkAnimal_ID = OO.Animal_ID) II) XX

If you don't know all the FK tables, you can use system meta-data tables to generate that collection of UNION ALL queries into a table, which you could then copy & paste into your query:

WITH AKT AS ( 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
              WHERE  f.referenced_object_id = object_id('Animal'))
SELECT 'SELECT ' + ColumnName + ' FROM ' + TableName + ' WHERE  RR.' + ColumnName + ' = OO.' + ReferenceColumnName + ' UNION ALL'
FROM   AKT

And for the whole thing in a single query using a recursive CTE:

DECLARE @QUERY NVARCHAR(MAX)

WITH AKT AS ( SELECT ROW_NUMBER() OVER (ORDER BY f.name) RN, f.name AS ForeignKey
                    ,OBJECT_NAME(f.parent_object_id) AS TableName
                    ,COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName
                    ,SCHEMA_NAME(oo.schema_id) SchemaName
                    ,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
                     INNER JOIN sys.objects oo ON oo.object_id = fc.referenced_object_id
              WHERE  f.referenced_object_id = object_id('Animal'))

    ,bs AS (SELECT AKT.RN
                  ,'SELECT ' + ColumnName + ' FROM ' + SchemaName + '.' + TableName + ' WHERE ' + ColumnName + ' = OO.' + ReferenceColumnName  SubQuery
            FROM   AKT)
    ,re AS (SELECT bs.RN, CAST(RTRIM(bs.SubQuery) AS VARCHAR(MAX)) Joined
            FROM   bs
            WHERE  bs.RN = 1
            UNION  ALL
            SELECT bs2.RN, CAST(re.Joined + ' UNION ALL ' + ISNULL(RTRIM(bs2.SubQuery), '') AS VARCHAR(MAX)) Joined
            FROM   re, bs bs2 
            WHERE  re.RN = bs2.RN - 1 )
    ,fi AS (SELECT ROW_NUMBER() OVER (ORDER BY RN DESC) RNK, Joined
            FROM   re)
SELECT @QUERY  = 'SELECT OO.Animal_ID, OO.Name, CASE WHEN XX.REFERENCED IS NULL THEN ''No'' ELSE ''Yes'' END Referenced
FROM   Animal OO
       OUTER APPLY (SELECT SUM(1) REFERENCED
                    FROM   (' + Joined + ') II) XX'
FROM   fi
WHERE  RNK = 1

EXEC (@QUERY)
like image 66
Griffin Avatar answered Oct 19 '22 10:10

Griffin