Search code examples
sqlsql-serverdynamic-programming

Comparing table names across multiple SQL Server databases


I am trying to run a SQL Server export which compares the table names listed in three or more databases on a SQL Server instance (actually the number is a lot higher!)

I can use something simple like the following to get a list of all of the tables in a particular database.

SELECT [name] 
FROM DB1.sys.tables 

What I would like to be able to do is to be able to join these for multiple databases to create a single view to spot differences (and similarities).

So for example if I have three databases with the following tables

DB1:

Customers
Orders
Products

DB2:

Products
Orders

DB3:

Products
Suppliers

How could I join them all together to get something like the following?

DB1 DB2 DB3
Customers NULL NULL
Orders Orders NULL
Products Products Products
NULL NULL Suppliers

Thanks!


Solution

  • This script should give you what you are looking for and can be easily extended by fiddling with the WHERE clause around line 20

    --Set up some global temporary tables
    CREATE TABLE ##all_tables(
        [database_name] sysname,
        [table_name] sysname
    )
    
    CREATE TABLE ##tables_for_relevant_dbs(
        [database_name] sysname,
        [table_name] sysname
    )
    
    --Capture a list of all the tables in all of the databases on the instance
    exec sp_MSforeachdb 'insert into ##all_tables select ''?'', [name] from [?].sys.tables'
    
    --Filter to get the tables from the relevant databases
    INSERT INTO ##tables_for_relevant_dbs 
        SELECT dbs.[database_name],tbls.[table_name]
        FROM (select distinct database_name from ##all_tables) dbs
        LEFT JOIN ##all_tables tbls on tbls.database_name=dbs.database_name
        WHERE dbs.database_name like '%' --PUT SOMETHING ELSE HERE
    
    --This magic TSQL concatenates a column of values into a single string
    --This string is then used in the dynamic pivoting below
    DECLARE @dblist VARCHAR(MAX)
    
    SELECT 
    @dblist = STUFF((SELECT ', [' + d_name + ']' AS [text()]
    FROM (SELECT DISTINCT 
    database_name d_name 
    FROM ##tables_for_relevant_dbs) d 
    ORDER BY d_name
    FOR XML PATH('')), 1, 1, '')
    
    --Pivot the data to turn the database names into columns
    EXEC ('SELECT ' + @dblist + '
    FROM (SELECT at1.database_name, at2.table_name src, at1.table_name dest
    FROM ##tables_for_relevant_dbs at1
    LEFT JOIN ##tables_for_relevant_dbs at2 on at2.database_name=at1.database_name and at2.table_name=at1.table_name) t
    PIVOT (max(t.src) FOR [database_name] IN (' + @dblist + ')) as [PVT]')
    
    --Clean up
    DROP TABLE ##all_tables
    DROP TABLE ##tables_for_relevant_dbs