Click here to Skip to main content
15,891,567 members
Articles / Database Development / SQL Server / SQL Server 2016
Tip/Trick

SQL Server: Find Table Order/Generation And Relation Details

Rate me:
Please Sign up or sign in to vote.
2.00/5 (1 vote)
29 May 2019CPOL1 min read 6.4K   77   3   1
A utility query to find table generations in SQL Server relational database

Introduction

While working with a relational database, I came into a point to find the relations between tables. The aim was to clean tables in proper order and sync data from another database, which lead me to a scenario to find table generation order.

Background

What are we going to do here?

  • Find the relation between tables.
  • Find the generation of each table.
    • Find first generation tables (tables having no foreign key, or it's own column as a foreign key).
    • Find the generation of remaining tables.

Temporary Tables

SQL
IF object_id('tempdb..#tblRelation') is not null
    DROP TABLE #tblRelation;
IF object_id('tempdb..#tblDetail') is not null
    DROP TABLE #tblDetail;

/*table relation details*/
CREATE TABLE #tblRelation (ObjectId VARCHAR(100) NOT NULL,
                            Name VARCHAR(100) NOT NULL,
                            [Schema] VARCHAR(100) NOT NULL,
                            [Column] VARCHAR(100) NOT NULL,
                            FkFromObjectId VARCHAR(100) NOT NULL,                            
                            FkFromTbl VARCHAR(100) NOT NULL,
                            FkFromSchema VARCHAR(100) NOT NULL,
                            FkFromClm VARCHAR(100) NOT NULL);

/*table generation details*/
CREATE TABLE #tblDetail (Name VARCHAR(100) NOT NULL,
                         [Schema] VARCHAR(100) NOT NULL,
                         Generation INT NULL);

Find Table Relation Details

Here, we are gathering relation between tables:

SQL
INSERT
    INTO #tblRelation
    SELECT
        parent_object_id,
        OBJECT_NAME(parent_object_id),
        OBJECT_SCHEMA_NAME(parent_object_id),
        c.NAME,
        referenced_object_id,
        OBJECT_NAME(referenced_object_id),
        OBJECT_SCHEMA_NAME(referenced_object_id),
        cref.NAME
    FROM 
        sys.foreign_key_columns fk
    INNER JOIN 
        sys.columns c 
           ON fk.parent_column_id = c.column_id 
              AND fk.parent_object_id = c.object_id
    INNER JOIN 
        sys.columns cref 
           ON fk.referenced_column_id = cref.column_id 
              AND fk.referenced_object_id = cref.object_id;

Find Table Generation Details

Now, it's time to find table generations using table relation data.

Find First Generation Tables

What is the first generation table?

  • Tables having no foreign key
  • Or only it's own column as a foreign key
SQL
/*find first generation table*/
INSERT 
    INTO #tblDetail(Name, [Schema], Generation)
    (SELECT 
        TABLE_NAME, 
        TABLE_SCHEMA,
        (CASE 
            WHEN(
            /*if tbl has no fk, first generation tbl, 0*/
            (SELECT COUNT(*) 
                FROM #tblRelation
                WHERE Name = TABLE_NAME AND [Schema] = TABLE_SCHEMA) = 0
            )
            THEN(SELECT 0)
            
            WHEN(
            /*if tbl has fk, but all of them from his own columns, 
              first generation tbl, 0*/
            (SELECT COUNT(*) 
                FROM #tblRelation
                WHERE Name = TABLE_NAME AND [Schema] = TABLE_SCHEMA) = 
            (SELECT COUNT(*) 
                FROM #tblRelation
                WHERE Name = TABLE_NAME
                    AND FkFromTbl = TABLE_NAME  AND [Schema] = TABLE_SCHEMA)        
            )
            THEN(SELECT 0)
            
            /*tbl has fk, from other tbl columns, NULL*/
            ELSE(SELECT NULL)
          END)    
        FROM INFORMATION_SCHEMA.TABLES 
            WHERE TABLE_TYPE = 'BASE TABLE'
            AND TABLE_NAME != 'sysdiagrams');

Find the Generation of Remaining Tables

Now let find the 1, 2, 3, ..... Nth generation tables.

SQL
/*set new generation using olds*/
WHILE(EXISTS(SELECT * 
                FROM #tblDetail 
                WHERE Generation IS NULL))
BEGIN

    /*find new generation tables*/
    DECLARE @tblNewGeneration TABLE(Name VARCHAR(100) NOT NULL,
                                    [Schema] VARCHAR(100) NOT NULL)                                
    /*Select tables where all of its foreign key table’s generation were found*/                            
    INSERT INTO @tblNewGeneration
    SELECT Name, [Schema]
        FROM #tblDetail AS dtl
        WHERE Generation IS NULL
        AND NOT EXISTS (
                SELECT DISTINCT FkFromTbl,FkFromSchema
                    FROM #tblRelation AS rel
                    WHERE rel.Name = dtl.Name 
                    AND rel.[Schema] = dtl.[Schema] 
                EXCEPT
                SELECT Name, [Schema]
                    FROM #tblDetail
                    WHERE Generation IS NOT NULL
        )

    /*set generation*/
    DECLARE @crntGeneration INT
    SET @crntGeneration = (SELECT MAX(Generation)  
                            FROM #tblDetail
                            WHERE Generation IS NOT NULL);                            
    UPDATE #tblDetail
        SET Generation = @crntGeneration + 1
        WHERE [Schema]+'.'+Name 
        IN (
            SELECT [Schema]+'.'+Name
                FROM @tblNewGeneration
        )
    
    /*clean the new generation tbls from temp*/    
    DELETE FROM @tblNewGeneration;
END;

Results

Table Generations

SQL
/*table generations*/
SELECT *
    FROM #tblDetail
    ORDER BY Generation, Name, [Schema];

Table Relations

SQL
/*table relations*/
SELECT *
    FROM #tblRelation
    ORDER BY Name, [Schema], FkFromTbl, FkFromSchema;

Unwanted Scenario

We may also find NULL as a generation or order value. It means there is a present of Circular Relations in the database and it is essential to redefine the table relations.

Limitation

The solution may vary depending on the database version. Our tested databases are

  • SQL Server-2008R2
  • SQL Server-2012
  • SQL Server-2014
  • SQL Server-2016

Please find the necessary SQL files as an attachment.

History

  • 29th May, 2019: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Bangladesh Bangladesh
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionIn case you encounter with "Cannot resolve the collation conflict ..." error Pin
Seyed Hossein Mirheydari2-Nov-20 6:27
Seyed Hossein Mirheydari2-Nov-20 6:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.