sql server

Muitos colegas já tiveram a necessidade de comparar duas bases de dados no SQL Server para analisar rapidamente a diferença entre elas.

Como é algo recorrente, estou publicando aqui uma consulta (query) que compara a estrutura de duas bases e destaca tabelas e campos que existem em uma e não na outra, bidirecionalmente.

Bases de exemplo

Imagine que você tem um BANCO_A:

use BANCO_A;
go

create table Person (
    id int primary key identity,
    name varchar(100),
    height numeric(4,1)
);

create table Car (
    id int primary key identity,
    brand varchar(100),
    model varchar(100),
    year int 
);

create table Animal (
    id int primary key identity,
    name varchar(100),
    kind varchar(100)
);

E também um BANCO_B:

use BANCO_B;
go

create table Person (
    id int primary key identity,
    name varchar(100)
);

create table Car (
    id int primary key identity,
    brand varchar(100),
    model varchar(100),
    year float,
    kilometers int
);

create table Pet (
    id int primary key identity,
    name varchar(100)
);

Verificando tabelas adicionadas e excluídas

Para identificar somente as tabelas que foram adicionadas ou excluídas de uma base para outra, use a seguinte consulta:

SELECT T1.TABLE_NAME 'DB1 TABLE', T2.TABLE_NAME 'DB2 TABLE'
FROM BANCO_A.INFORMATION_SCHEMA.TABLES T1 
FULL JOIN BANCO_B.INFORMATION_SCHEMA.TABLES T2 
    ON T1.TABLE_NAME = T2.TABLE_NAME
ORDER BY ISNULL(T1.TABLE_NAME, T2.TABLE_NAME)

Verificando colunas adicionadas e excluídas

Para verificar as diferenças tanto das tabelas como das colunas que elas contém, use a seguinte consulta:

SELECT DB1.TABLE_NAME 'DB1 TABLE', DB1.COLUMN_NAME 'DB1 COLUMN', DB1.DATA_TYPE 'DB1 TYPE',
    DB2.TABLE_NAME 'DB2 TABLE', DB2.COLUMN_NAME 'DB1 COLUMN', DB2.DATA_TYPE 'DB2 TYPE'
FROM (
    SELECT T1.TABLE_NAME, C1.COLUMN_NAME, C1.DATA_TYPE
    FROM BANCO_A.INFORMATION_SCHEMA.TABLES T1 
    JOIN BANCO_A.INFORMATION_SCHEMA.COLUMNS C1 
        ON C1.TABLE_NAME = T1.TABLE_NAME
    ) DB1
FULL JOIN (
    SELECT T2.TABLE_NAME, C2.COLUMN_NAME, C2.DATA_TYPE
    FROM BANCO_B.INFORMATION_SCHEMA.TABLES T2 
    JOIN BANCO_B.INFORMATION_SCHEMA.COLUMNS C2 
        ON C2.TABLE_NAME = T2.TABLE_NAME
    ) DB2
    ON DB1.TABLE_NAME = DB2.TABLE_NAME
    AND DB1.COLUMN_NAME = DB2.COLUMN_NAME
ORDER BY ISNULL(DB1.TABLE_NAME, DB2.TABLE_NAME), ISNULL(DB1.COLUMN_NAME, DB2.COLUMN_NAME)

Executando a consulta dinamicamente

Nos dois exemplos acima, basta trocar BANCO_A e BANCO_B por duas bases que você precisa comparar.

Entretanto, pode ser que você queira criar uma procedure ou rotina que compare duas bases quaisquer.

Para isso você pode executar uma consulta dinâmica usando o comando SP_SQLEXEC. Veja o seguinte exemplo:

DECLARE 
    @BANCO1 NVARCHAR(100) = 'BANCO_A',
    @BANCO2 NVARCHAR(100) = 'BANCO_B',
    @SQL NVARCHAR(2000)

SET @SQL = N'SELECT T1.TABLE_NAME ''DB1 TABLE'', T2.TABLE_NAME ''DB2 TABLE''
    FROM ' + @BANCO1 + '.INFORMATION_SCHEMA.TABLES T1 
    FULL JOIN ' + @BANCO2 + '.INFORMATION_SCHEMA.TABLES T2 
        ON T1.TABLE_NAME = T2.TABLE_NAME
    ORDER BY ISNULL(T1.TABLE_NAME, T2.TABLE_NAME)';

EXEC sp_sqlexec @SQL

Agora basta alterar o valor das variáveis ou receber os nomes das duas bases através de parâmetros.

Duas observações importantes:

  1. O parâmetro da rotina SP_SQLEXEC deve ser do tipo NVARCHAR.
  2. Não tente fazer a concatenação de variáveis e literais diretamente no argumento dessa rotina. Faça isso sempre antes e então passe uma variável como argumento. Não fiz o teste em todas as versões do SQL Server, mas nas que usei deve ser desta forma.