Desenvolvimento - Visual Basic

Simplifique a Extração de Dados

Utilize um modelo simples de objeto baseado em ODBC para extrair e manipular os dados do SQL Server.

por John Cartin



Provavelmente, em algum momento, você precisou extrair dados de um banco de dados, no intuito de mover os dados para um outro banco de dados ou criar um backup. Os utilitários para extração vêm junto com cada sistema de gerenciamento de banco de dados relacional (RDBMS - Relational Database Management System), mas eles diferem um do outro e exigem que você utilize diferentes interfaces e metodologias. O que você realmente necessita é de uma ferramenta que extraia os dados de qualquer conexão baseada em ODBC para um banco de dados de formato padrão. Então, você poderá importar estes dados para um outro banco de dados ou arquivá-los para utilização posterior.

Mostraremos como construir uma ferramenta simples de extração de dados baseada no ActiveX Data Objects (ADO) 2.5, que obtém os dados de um banco de dados, tais como SQL Server ou Oracle, e constrói as instruções de inserção SQL dos dados recuperados. Você poderá colocar essas instruções de inserção em outro banco de dados, em qualquer plataforma, ou utilizá-lo como arquivo morto.

Levou algum tempo para que as consultas que eu gravei para a ferramenta funcionassem bem; precisava saber quais campos eram válidos no ambiente de destino e se os valores da chave primária se encaixavam. Para resolver esses problemas, expandi a extração incluindo um modelo de objeto capaz de manipular os dados utilizados na construção das instruções de inserção. O modelo de objeto lhe permite remover certos campos, como por exemplo os campos do tipo Identity, e adicioná-los novamente. Você poderá adicionar novos campos às instruções e salvá-los como arquivos de consulta em lotes (batch) para que possa executá-los mais tarde. Finalmente, você poderá formatar os dados em um banco de dados compatível com os tipos de dados - SQL Server ou Oracle. Esses recursos tornam os dados mais fáceis de serem transportados.

A ferramenta de extração de dados utiliza um recordset ADO para recuperar dados do SQL Server. Se uma instrução SQL está presente, o ADO cria um recordset com o atributo Cursor-Location ajustado para adUseClient. Você terá que criar o recordset desse modo, quando utilizar um disconnected recordset, que significa um recordset sem conexão ativa para a fonte de dados. Se o ADO gerar qualquer sintaxe de erro SQL, após criar o recordset de uma consulta, a ferramenta de extração de dados capta a falha e, por conseguinte, notifica o usuário.

Esse tipo de recordset é muito mais eficiente para se trabalhar num ambiente desktop, porque ele não ocupa os recursos necessários para manter uma conexão ativa com o banco de dados. Ao desconectar o recordset de sua fonte de dados, o atributo RecordCount mantém o valor correto. Se o recordset ainda estiver conectado, o atributo RecordCount terá um valor de -1. Uma vez criado o recordset através da ferramenta de extração, ela abre o recordset assim:

Listagem 1: Abrindo o recordset

m_oRS.Open SQL, m_oConn,
	adOpenDynamic, adLockOptimistic

Quando o recordset retornar com os dados, a ferramenta de extração armazena-os numa coleção de objetos de registro personalizado, que contém uma coleção de objetos de campo. Esse método de armazenamento de dados é importante, porque você tem dois obstáculos que necessitam de atenção. Primeiro, a ferramenta de extração de dados tem que ser rápida; o desempenho é sempre uma prioridade ao escrever qualquer aplicativo. Segundo, o código tem que expor um fácil acesso programático aos dados para modificar apropriadamente o seu estado. O método de armazenamento de dados encontra um equilíbrio ao adicionar desempenho, sem afetar a eficácia do código ao modificar o estado do objeto.

Formatando os Dados

Uma vez armazenados os dados, inicia-se o verdadeiro trabalho. Para que eles tenham um valor real, você precisará formatá-los em instruções de inserção SQL. Além disso, se você quiser acompanhar as técnicas modernas de orientação a objetos, faz sentido o nível mais baixo de objeto lógico fazer sua própria formatação. Neste caso, o objeto CRecord é o que melhor se encaixa para manipular a formatação, em vez do objeto CField, porque o CRecord tem que lidar com os valores das colunas e dados em cada instrução de inserção. O modelo ADO oferece uma maneira fácil de entender o tipo de dado de cada valor; a enumeração ADODB.DataTypeEnum fornece o método perfeito para se fazer exatamente isso.

Todos os campos em um recordset possuem um atributo Type que associa o tipo de dado do campo ao tipo de dado listado na enumeração ADO DataTypeEnum. Esse atributo pode ser qualquer valor ADO válido, como adInteger, adDate, ou adVarChar (consulte a Tabela 1). A lógica resultante pode suportar a quantidade de tipos de dados que você escolher: mais ou menos. Escolhemos poucos tipos de dados comuns: adInteger, adDate, adVarChar, adVarBinary, adChar e suas variantes associadas.

Tabela 1: Escolhendo um dos tipos de dados ADO. Esses tipos de dados ActiveX Data Objects (ADO) disponíveis foram obtidos através da plataforma Microsoft SDK. Na sua ferramenta de extração, você poderá escolher os tipos de dados que lhe convier.

Constante Descrição
adArray Valor de sinalização associado à outra constante
adBigInt Inteiros sinalizados de 8 bytes
adBinary Valor binário
adBoolean Valor booleano
adBSTR Cadeia de caracteres com terminação nula (Unicode)
adChapter Valor de módulo de 4 bytes identificando linhas num child rowset
adChar Valor de string
adCurrency Valor de moeda
adDate Valor de data
adDBDate Valor de data (yyyymmdd)
adDBTime Valor de tempo (hhmmss)
adDBTimeStamp Estampa de data/tempo (yyyymmddhhmmss)
adDecimal Valor numérico exato com precisão e escala fixas
adDouble Ponto flutuante de precisão dupla
adEmpty Sem valor
adError Código de erro de 32 bits
adFileTime Valor de 64 bits representando 100 nanossegundos desde 10 de janeiro de 1601
adGUID Identificador Único Global (Globally Unique Identifier)
adIDispatch Ponteiro para uma interface IDispatch de um objeto COM
adInteger Inteiros sinalizados de 4 bytes
adIUnknown Ponteiro para uma interface IUnknown de um objeto COM
adLongVarBinary Valor binário longo
adLongVarChar Valor de string longo
adLongVarWChar Cadeia de caracteres extensa com terminação nula (Unicode)
adNumeric Valor numérico exato com precisão e escala fixas
adPropVariant Automação PROP_VARIANT
adSingle Ponto flutuante de precisão simples
adSmallInt Inteiros sinalizados de 2 bytes
adTinyInt Inteiros sinalizados de 1 byte
adUnsignedBigInt Inteiros não sinalizados de 8 bytes
adUnsignedInt Inteiros não sinalizados de 4 bytes
adUnsignedSmallInt Inteiros não sinalizados de 2 bytes
adUnsignedTinyInt Inteiros não sinalizados de 1 byte
adUserDefined Variável definida pelo usuário
adVarBinary Valor binário
adVarChar Valor de string
adVariant Variante de automação
adVarNumeric Valor numérico
AdVarWChar Cadeia de caracteres com terminação nula (Unicode)
adWChar String de cadeia de caracteres com terminação nula (Unicode)

Essa ferramenta de extração de dados suporta as regras de sintaxe do SQL Server 7.0, mas oferecendo suporte Oracle, a ferramenta se torna mais útil. Para a maioria dos tipos de dados, SQL Server e Oracle são essencialmente os mesmos; a maior diferença entre os dois é em como eles formatam as datas. A sintaxe do SQL Server para a inserção de datas é simples: o valor da data fica entre aspas simples (‘) . A versão Oracle para o tipo de dado de data depende da função To_DATE() (consulte a seção Fontes de Referência). Você fornecerá suporte para ambos os servidores de banco de dados através de uma variável global no código, baseada no servidor que o usuário direciona. Uma vez conhecendo a plataforma alvo, a função que formata as instruções de inserção escolhe a regra a ser utilizada.

O resultado final da formatação é que a ferramenta de extração de dados recupera as instruções de inserção e adiciona-os à interface do usuário (User Interface - UI). Você realizará essa tarefa através de uma série de loops (um loop dentro do outro). Ao chamar o método GetFormattedData() do objeto CRecord no objeto CConn, você consultará cada objeto CField para cada nome, tipo e valor de campo. Baseado nestes valores, você criará essa instrução de inserção:

Listagem 2: Instrução de inserção

INSERT INTO [TABLE NAME] ([COLUMN
	LIST]) VALUES ([VALUE LIST])

No objeto CRecord, cada objeto CField retorna seu nome de coluna e valor de campo para ser isolado numa variável privada do objeto CRecord. A função determina o tipo de dado do campo baseado no atributo Type, comparando o campo à enumeração ADO DataTypeEnum. Uma vez determinado o valor do campo, ele será formatado baseado nas regras de sintaxe para o tipo de dado da plataforma do banco de dados escolhida; o valor é formatado apropriadamente (consulte a Listagem 1).

Listagem 3: Essa função de formatação baseada no tipo de dado

Private Function FormatField(FieldName As _
	String, FieldType As ADODB.DataTypeEnum, _
	FieldValue as Variant)

	If Len(FieldName) = 0 Then
		Err.Raise vbObjectError + 2007, , _
			"No Field Name was specified for record."
	Else
		Select Case FieldType
			Case ADODB.adChar
				m_ValueString = m_ValueString & _
					""" & FieldValue & "", "
			Case ADODB.adWChar
				m_ValueString = m_ValueString & _
					""" & FieldValue & "", "
			Case ADODB.adVarChar
				m_ValueString = m_ValueString & _
					""" & FieldValue & "", "
			Case ADODB.adVarWChar
				m_ValueString = m_ValueString & _
					""" & FieldValue & "", "
			Case ADODB.adLongVarWChar
				m_ValueString = m_ValueString & _
					""" & FieldValue & "", "
			Case ADODB.adDate
				m_ValueString = m_ValueString & _
					""" & FieldValue & "", "
			Case ADODB.adInteger
				m_ValueString = m_ValueString & _
					""" FieldValue & ", "
		End Select
	End If

Assim que a coleção no objeto CRecord consulta cada objeto CField e a função de formatação preenche os buffers privados, sua ferramenta de extração de dados coloca as instruções de inserção juntas e retorna ao objeto CConn. Após a consulta de cada objeto CRecord em seus valores, você escreverá a string resultante na UI, onde poderá ser manipulada ou salva. Após cada objeto CRecord executar um loop através de suas coleções de objetos CField, ele ocupa um buffer contendo as instruções de inserção prontas. Você concatenará e escreverá essas instruções na UI tanto quanto as instruções de inserção SQL separadas pela palavra-chave GO do SQL Server.

Além de salvar as instruções de inserção, a ferramenta de extração de dados também salva o objeto Recordset no formato XML (Extensible Markup Language). O aplicativo realiza a tarefa chamando o método Save() do objeto Recordset e fornece os parâmetros para o caminho do arquivo e PersistFormat - nesse caso, adPersistXML. Você poderá visualizar o código fonte XML em qualquer editor de texto. Por exemplo, o conteúdo da tabela Regions no banco de dados Northwind demonstra a saída XML do recordset.

Quando o usuário clicar no menu Save, a ferramenta de extração de dados exibirá uma caixa de diálogo onde você especificará o caminho e o nome do arquivo. A ferramenta então chamará o método Save do recordset e salvará as instruções de inserção, utilizando o método Save do controle Rich TextBox. Também salvará ambos os arquivos XML do recordset e o arquivo de texto contendo as instruções de inserção, utilizando os mesmos nomes, porém com extensão ORS. Você poderá exportar ambas as instruções de inserção para um banco de dados de destino e o recordset não processado, do qual foi criado.

A ferramenta de extração de dados utiliza arquivos XML para retornar o recordset ao seu estado original e constrói instruções de inserção, como se o recordset fosse construído através de dados reais num banco de dados. Encontrei uma característica pouco comum quando a ferramenta reconstruiu o recordset do arquivo XML: o recordset armazena alguns tipos de dados diferentemente dos outros. Por exemplo, o XML armazena um valor adVarChar como um adVarWChar (uma string de caracteres longos). A plataforma SDK descreve o tipo de dado do adVarWChar como uma cadeia de caracteres com terminação nula Unicode. Você poderá resolver esse problema específico, incluindo o tipo de dado adWVarChar na função de formatação, e a função desempenhará a mesma formatação que é feita para o tipo de dado do adVarChar.

Recuperar o recordset já salvo é simples. Um recordset ADO recupera o seu estado e os dados do arquivo XML; esse arquivo retorna o recordset para o estado exato em que foi salvo. Uma vez feito, a ferramenta o leva através dos mesmos passos que o recordset criado de uma consulta para retornar as instruções de inserção. Quando a ferramenta de extração de dados retorna as instruções de inserção finalizadas, você pode manipular os dados como quiser.

É prático remover campos e adicionar novos. E remover um campo de chave primária de uma consulta poupa tempo, mas a verdadeira mágica de uma ferramenta de extração de dados é a capacidade de adicionar um novo campo de valor em todas as instruções de inserção.

Sobre o Autor

John Cartin mora em Columbia, S.C., é desenvolvedor em tempo integral na VC3 Inc., estudante de Shaolin kung-fu e um médio jogador de futebol.

Download do código referente a este artigo

Clique aqui para fazer o download.
John Cartin

John Cartin