Banco de Dados

2 jul, 2013

Scripts e tabelas de catálogo 04: identificando campos por seu conteúdo no SQL Server

Publicidade

No artigo anterior, eu apresentei como localizar um campo num banco de dados do SQL Server 2012 conhecendo apenas o nome do campo. Mas existem situações em que precisamos identificar um campo em que nem mesmo o nome é conhecido.

Algumas vezes, os usuários precisam de ajuda para identificar campos (seu nome, tabela e esquema), sabendo apenas o conteúdo do campo. Usuários não têm culpa se os bancos de dados são mal documentados e/ou se o arquiteto do banco saiu da empresa. E você, como DBA e profissional dedicado, precisa encontrar soluções para os problemas da empresa.

O script que apresento a seguir foi criado para solucionar esse tipo de cenário. A ideia aqui é usar tabelas de sistemas para gerar uma consulta SQL que fará a pesquisa em todos os campos que suportam o tipo de dados pesquisado. Ou seja, o script resolve o problema pela “força bruta”.

O exemplo a seguir usa a base AdventureWorks2012 e faz uma varredura de todos os campos com tipos de dados que aceitem cadeias de caracteres para encontrar qual deles contém a palavra “Paul”.

Para isso, eu usei as seguintes tabelas:

  • sys.schemas
  • sys.all_objects
  • sys.all_columns
  • sys.types

A seguir, eu descrevo em detalhes como funciona a consulta nas tabelas de sistema e como ela gera o texto equivalente ao script de uma nova consulta:

  1. a consulta nas tabelas de sistema gera uma nova e única declaração SQL, que então será usada para pesquisar todos os campos desejados
  2. a consulta nas tabelas de sistema concatena cadeias de caracteres fixos e os valores dos campos das próprias tabelas de sistema, de tal modo que cada registro da listagem final é, por si só, uma nova declaração SQL
  3. ao final de cada linha da listagem, teremos a palavra UNION para que a declaração SQL dessa linha possa ser executada junto com a declaração da linha seguinte
  4. para facilitar a lógica da consulta, deve-se lembrar que o último registro da listagem também inclui a palavra UNION, mas esta deve ser desconsiderada quando a nova declaração for executada
  5. apenas tabelas de usuário precisam ser consultadas (sys.all_objects.type = ‘U’)
  6. são considerados apenas campos cujo tipo de dados aceite cadeias de caracteres (sys.types in (CHAR, VARCHAR, NCHAR & NVARCHAR))
  7. nas consultas geradas, a palavra “Paul” pode ser encontrada em qualquer posição do campo ( campo like ‘%Paul%’)
  8. as consultas geradas devem funcionar mesmo quando tabelas e/ou campos tenham nomes com espaços em branco (escrever nomes de tabelas e campos entre  chaves ‘[‘ e ‘]’)

Juntando tudo isso, temos a seguinte consulta:

SELECT 
     'select ''[' + S.NAME + ']'' AS ESQUEMA, ''[' + O.NAME + ']'' AS TABELA, '
     + '''[' + C.NAME + ']'' AS COLUNA ' 
     + ' from [' + S.NAME + '].[' + O.NAME + ']'
     + ' where [' + C.NAME + '] like ''%Paul%'' union '
FROM SYS.ALL_OBJECTS O
      INNER JOIN SYS.SCHEMAS S ON O.SCHEMA_ID = S.SCHEMA_ID
   INNER JOIN SYS.ALL_COLUMNS C ON O.OBJECT_ID=C.OBJECT_ID
   INNER JOIN SYS.TYPES T ON C.USER_TYPE_ID=T.USER_TYPE_ID
WHERE O.TYPE='U'
      AND T.NAME IN ('char', 'nchar', 'varchar', 'nvarchar')
ORDER BY S.NAME, O.NAME, C.NAME

Essa consulta gerou um script de 71 linhas. Para fins ilustrativos, mostro a seguir a primeira e a última linha do script, já considerando que a palavra UNION precisa ser excluída manualmente da última linha do script.

 

select '[dbo]' AS ESQUEMA, '[AWBuildVersion]' AS TABELA, '[Database 
Version]' AS COLUNA from [dbo].[AWBuildVersion] where [Database Version] 
like '%Paul%' union 
...
select '[sys]' AS ESQUEMA, '[trace_xe_event_map]' AS 
TABELA, '[xe_event_name]' AS COLUNA from [sys].[trace_xe_event_map] where 
[xe_event_name] like '%Paul%'

Finalmente, eu executo essa consulta para obter a listagem de todos os campos e tabelas do banco de dados AdventureWorks2012 que possuem a palavra “Paul” em seu conteúdo, como mostro a seguir.

ESQUEMA                            TABELA                                COLUNA

—————- ————————————— ————————-

[HumanResources] [Employee]                           [LoginID]

[Person]                             [Address]                              [AddressLine1]

[Person]                            [EmailAddress]                    [EmailAddress]

 

(3 row(s) affected)

Graças a esse recurso, foi possível reduzir a pesquisa de identificação de um campo a apenas 3 possíveis candidatos, o que facilita enormemente o trabalho.

Contudo, é importante observar que esta é uma consulta pesada. Ela pesquisa todos os campos do tipo cadeia de caracteres usando o operador LIKE, que por si só já tem um impacto significativo em performance.

Sendo assim, é recomendável que se tenha o cuidado de executar consultas dessa natureza em horários em que o banco de dados tenha pouca atividade.

Por hoje é só, espero que tenha gostado desta dica. Até a próxima!