Comparing table names across multiple SQL Server databases

Viewed 54

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!

2 Answers

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

using common table expression to get table names in the information schema table and full outer join does the trick.

;with tables_in_DB1 as
(
select * from DB1.INFORMATION_SCHEMA.TABLES
where TABLE_TYPE='BASE TABLE'
), 
tables_in_DB2 as
(
select * from DB2.INFORMATION_SCHEMA.TABLES
where TABLE_TYPE='BASE TABLE'
), 
tables_in_DB3 as
(
select * from DB3.INFORMATION_SCHEMA.TABLES
where TABLE_TYPE='BASE TABLE'
) 

select db1.table_name as DB2,db2.table_name as DB2,
db3.table_name as DB3 from tables_in_DB1 db1 
full outer join tables_in_DB2 db2 on db1.TABLE_NAME=db2.TABLE_NAME 
full outer join tables_in_DB3 db3 on db2.TABLE_NAME=db3.TABLE_NAME
Related