Comparando tabelas no SQL Server
Autor: Elton de Freitas | Publicado: 2012-10-21T07:40:00-07:00



&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;E ai pessoal beleza? Estava meio sumido, mas venho com
mais uma dica interessante. Recentemente tive que comparar a estrutura de
algumas tabelas para fazer merge entre as mesmas (juntar os dados), para isso
precisei comparar a estrutura das mesmas para ver se tinha condição de fazer
isso. Tenho um projeto em Integration Services que faz o merge automaticamente
para mim, só que ele ainda não compara a estrutura das tabelas, ele parte do
principio que as mesmas são iguais. então resolvi construir queries que
fizessem o trabalho sujo de comparar a estrutura para mim.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Existe um utilitário de linha de comando do SQL Server
que faz a comparação entre tabelas, muito bom por sinal, mas meio enjoado de
ficar utilizando (minha opinião), ele se chama tablediff, em um post
futuro vou falar sobre ele.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Seguinte, no SQL Server existe a possibilidade de
verificar a estrutura das tabelas que existem nos bancos de dados por meio de
comandos SQL, são metadados das tabelas existentes, que podem ser consultados
na sys.[catalogo], neste exemplo vou
trabalhar com a sys.objects e com a sys.tables para realizar a operação que
desejo.



Para ficar fácil o
entendimento do exemplo, vou criar duas tabelas bem simples:



--CRIA TABELA TEMP1 E TEMP2

create table
temp1 (id int, nome varchar(50),snome varchar(50), altura float)

create table
temp2 (id int, nome varchar(50),snome varchar(50), altura float)



--INSERE DADOS EM TEMP1 E TEMP2

insert into
temp1 values(1,'fulano','de tal',1.5)

insert into
temp1 values(2,'beltrano','de tal',1.6)

insert into
temp1 values(3,'ciclano','de tal',1.7)



insert into
temp2 values(1,'fulano','de tal',1.5)

insert into
temp2 values(2,'beltrano','de tal',1.6)

insert into temp2 values(3,'ciclano','de tal',1.7)



Dando um select nas mesmas, depois de criadas elas ficarão da seguinte forma:



--SELECT NAS TABELAS TEMP1 E TEMP2

select * from
temp1

select * from temp2




Figura&nbsp;1&nbsp;- Select nas tabelas


<!--[if gte vml 1]><v:shapetype
 id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t"
 path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
 
 
  
  
  
  
  
  
  
  
  
  
  
  
 
 
 
<v:shape id="Imagem_x0020_0" o:spid="_x0000_i1029" type="#_x0000_t75"
 alt="select.png" style='width:151.5pt;height:154.5pt;visibility:visible;
 mso-wrap-style:square'>
 <v:imagedata src="file:///C:\Users\mlucia\AppData\Local\Temp\msohtmlclip1\01\clip_image001.png"
  o:title="select"/>
<![endif]--><!--[if !vml]--><!--[endif]-->



Observe na figura 1, são tabelas pequenas e muito
simples, podem ser comparadas rapidamente sem nenhum esforço, mas imagine uma
tabela com mais de trinta colunas e diferentes tipos, no meu caso, tenho essa
situação, então preciso agilizar meu serviço.



&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Primeiro, preciso saber o object_id de cada tabela no banco de dados que estou trabalhando,
esse object_id&nbsp; é a identificação interna da tabela no banco
de dados, é um metadado da tabela criada.

Para descobrir os object_id de todas as tabelas de um
banco de dados, deve ser usada a seguinte querie:



select * from sys.objects where type = 'u'

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

&nbsp;Porém, se o banco de dados que estiver sendo utilizado possuir
muitas tabelas, vai ficar meio confuso de verificar o object_id do que realmente interessa, então é bom especificar o
nome das tabelas desejadas, como as tabelas criadas no exemplo começam com
temp, utilizo um like para filtrar:



--TRAZ INFORMAÇÕES MAIS BÁSICAS DAS TABELAS CRIADAS

select * from sys.objects where name like 'temp%'



--TRAZ INFORMAÇÕES MAIS DETALHADAS DAS TABELAS CRIADAS

select * from sys.tables where name like 'temp%'




Figura&nbsp;2&nbsp;- Informações sobre as tabelas


<!--[if gte vml 1]><v:shape id="Imagem_x0020_1"
 o:spid="_x0000_i1028" type="#_x0000_t75" alt="INFO_TAB.png" style='width:425.25pt;
 height:62.25pt;visibility:visible;mso-wrap-style:square'>
 <v:imagedata src="file:///C:\Users\mlucia\AppData\Local\Temp\msohtmlclip1\01\clip_image003.png"
  o:title="INFO_TAB"/>
<![endif]--><!--[if !vml]--><!--[endif]-->



Observando a figura 2, é possível
verificar o object_id das tabelas
tanto em sys.objects, quanto em sys.tables, a diferença é a quantidade
de metadados que são apresentados em cada select.



&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Se fizer o seguinte select nas tabelas, é possível verificar
a estrutura das mesmas, por meio dos seus metadados, porém ainda não é o ideal,
como disse anteriormente, imagine duas tabelas muito grandes.

&nbsp;&nbsp;

-- VERIFICANDO NOME, TIPO, TAMANHO E COLLATE DAS TABELAS
CRIADAS

select name,system_type_id,max_length,collation_name
from sys.columns where object_id = 5575058

select name,system_type_id,max_length,collation_name
from sys.columns where object_id = 21575115




Figura&nbsp;3&nbsp;- Dados da estrutura da tabela


<!--[if gte vml 1]><v:shape id="Imagem_x0020_2"
 o:spid="_x0000_i1027" type="#_x0000_t75" alt="dados_tab.png" style='width:295.5pt;
 height:171pt;visibility:visible;mso-wrap-style:square'>
 <v:imagedata src="file:///C:\Users\mlucia\AppData\Local\Temp\msohtmlclip1\01\clip_image005.png"
  o:title="dados_tab"/>
<![endif]--><!--[if !vml]--><!--[endif]-->



Na figura 3 já é
possível ver se as tabelas são iguais em sua estrutura, mas como disse
anteriormente não é o ideal, então podemos melhorar a querie para o que
desejamos.



&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Vou verificar se os campos de uma tabela estão contidos
dentro da outra, se as duas forem iguais ou todos os campos da tabela de origem
estiverem contidos na tabela de destino, o resultado será vazio, se forem
diferentes, eles serão apresentados no resultado do select.



--VERIFICA SE NOMES DOS CAMPOS SÃO IGUAIS

select name from
sys.columns where object_id in

(

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select object_id from sys.tables where name = 'temp2'

)and name not
in

(

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select name from sys.columns where object_id in

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select object_id from sys.tables where name = 'temp1'

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )

)


Figura&nbsp;4&nbsp;- Comparando os campos


<!--[if gte vml 1]><v:shape id="Imagem_x0020_3"
 o:spid="_x0000_i1026" type="#_x0000_t75" alt="compara_campos.png" style='width:399pt;
 height:237pt;visibility:visible;mso-wrap-style:square'>
 <v:imagedata src="file:///C:\Users\mlucia\AppData\Local\Temp\msohtmlclip1\01\clip_image007.png"
  o:title="compara_campos"/>
<![endif]--><!--[if !vml]--><!--[endif]-->



A figura 4 demonstra o
resultado da comparação entre as duas tabelas, e o resultado é vazio, quer
dizer que as duas tabelas possuem os mesmos campos, mas ainda não me diz se a
estrutura é a mesma, quer dizer que ainda não é o ideal, então faço da seguinte
forma:



--VERIFICA SE OS CAMPOS E TIPOS DOS CAMPOS SÃO IGUAIS ENTRE
DUAS TABELAS

select sc1.name,sc1.system_type_id,sc1.max_length,sc1.collation_name from sys.columns sc1 

join sys.columns sc2 on 

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc1.name = sc2.name and 

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc1.system_type_id &lt;&gt;
sc2.system_type_id 

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and sc1.max_length &lt;&gt; sc2.max_length

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and sc1.collation_name
&lt;&gt; sc2.collation_name

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and sc2.object_id =
5575058

where sc1.object_id =
21575115



Observe que a querie acima é mais trabalhada, nela já
utilizo o object_id que descrevi anteriormente
e comparo os tipos de campos das tabelas, verificando se o id do tipo de campo
é diferente, se o tamanho é diferente e se o collate é diferente. Caso não exista nenhuma diferença entre as
tabelas, nenhum resultado será retornado.




Figura&nbsp;5&nbsp;- Comparação de tipos dos campos da tabela


<!--[if gte vml 1]><v:shape id="Imagem_x0020_5"
 o:spid="_x0000_i1025" type="#_x0000_t75" alt="compara_tabelas.png" style='width:425.25pt;
 height:153pt;visibility:visible;mso-wrap-style:square'>
 <v:imagedata src="file:///C:\Users\mlucia\AppData\Local\Temp\msohtmlclip1\01\clip_image009.png"
  o:title="compara_tabelas"/>
<![endif]--><!--[if !vml]--><!--[endif]-->



Assim é possível
verificar se duas tabelas são iguais, seja comparando apenas os nomes dos
campos, ou obtendo dados mais detalhados dos tipos de campos das tabelas. 

Para mim, essas queries
foram muito úteis, espero que possa ajudar a outras pessoas também.









Referências:



Catalog Views (Transact-SQL):&nbsp;http://msdn.microsoft.com/pt-br/library/ms174365.aspx

sys.objects (Transact-SQL):&nbsp;http://msdn.microsoft.com/pt-br/library/ms190324.aspx

sys.tables (Transact-SQL):&nbsp;http://msdn.microsoft.com/pt-br/library/ms187406.aspx

OBJECT_ID (Transact-SQL):&nbsp;http://msdn.microsoft.com/pt-br/library/ms190328.aspx

Metadados:&nbsp;http://pt.wikipedia.org/wiki/Metadados