segunda-feira, 10 de janeiro de 2011

Criando scripts parametrizáveis

Scripts dinâmicos são aqueles criados em tempo de execução de uma consulta do SQL Server e são importantes ferramentas para tornar o desenvolvimento mais flexivel e muitas vezes mais otimizado.

Assim como acontece com as Stored Procedures, o SQL Server permite a criação dinâmica de batches parametrizáveis, isto é, pode-se criar scripts que recebem valores através de parâmetros. Scripts de manutenção, ou de consulta mais complexos (aqueles que não pertencem a sistemas e também convém encapsular em stored procedures) podem ser executados dessa forma. 
Utilizaremos a stored procedure de sistema sp_executesql para  realizar esta tarefa, muito conhecida para a execução de scripts armazenados em strings. A sintaxe utilizada será:

exec sp_executesql @script, @params, @param1, @param2, ... @paramN

Neste caso, @script é uma string contendo o conteúdo do script, @paramsé uma string contendo os nomes e tipos dos parâmetros, e os parâmetros @param1, @param2, ... @paramN representam os N parâmetros definidos em @params.

O exemplo abaixo mostra como parametrizar um script no SQL Server:

 /* Declarando os parâmetros e seus respectivos tipos */
DECLARE @vars NVARCHAR (100)
SET @vars = '@valor CHAR(30)'

/* Declarando o conteúdo do script, utilizando o parâmetro definido acima */
DECLARE @script NVARCHAR(100)
SET @script = 'PRINT ''Exibindo o valor do parâmetro: '' + @valor'

/* Executando o script passando o parâmetro declarado */
exec sp_executesql @script, @vars, '$valor$'

Na figura abaixo, observamos o script acima em execução. Observe que o valor passado foi utilizado durante a execução do script:


Observações:
  • A stored procedure sp_executesql pode rodar apenas um batch por execução, ou seja, não é possível adicionar o comando "GO" ao script passado por parâmetro.

5 comentários:

Rubens disse...

Olá Evandro,

Gostei muito do seu artigo Parabéns. Lendo-o imaginei: Quem sabe vc não pode me ajudar a decifrar aqui um grande dilema que estou vivendo. Preciso enviar registros de vendas que estão num servidor local: SqlServer-> BDFrente para outro servidor remoto no mesmo ambiente de rede, na mesma empresa, mas numa base que deverá ser acessada via rede: SqlServer-> BDRetaguarda. Meus 2 Sistemas(Frente e Retaguarda) foram feitos em VB6 e ora eu vou estar enviando vendas do Frente para o Retaguarda outra ora eu quero receber no Frente as Tabelas Cadastrais vindas do Retaguarda.
Então lhe pergunto qual o melhor método e os passos para eu atingir esse objetivo? Iniciei pensando em Stored Procedure, até consegui abrir conexão com o ado.connection no Frente para o Retaguarda, mas não consegui foi incluir dados nessa base externa, nem editá-los etc...
Vc tem algum exemplo para essa situação ou poderia me indicar um método eficiente prático e mais seguro?

Grande abraço do amigo Rezende! rezendego@hotmail.com

Evandro disse...

Olá Rubens!

Primeiramente, agradeço a sua visita e o seu contato! Espero que eu possa te ajudar a resolver o seu problema.

Já me deparei com situações parecidas com esta algumas vezes, tanto para migrar a base de sistemas legados quanto para criar integrações entre sistemas via banco de dados.

Preciso de algumas informações adicionais para poder ajudar-lhe:

1-) Os dois bancos de dados estão rodando o SQL Server? Em caso afirmativo, rodam a mesma versão?

2-) A estrutura das tabelas nos dois bancos de dados é a mesma?

3-) Os dois bancos precisam estar sincronizados com os mesmos dados? Ou existem registros que só devem existir em um dos bancos?

4-) Você pretende desenvolver esta solução inteiramente em banco de dados? Ou planeja criar uma aplicação/serviço para desempenhar esta tarefa? Pelo que eu entendi, você está tentando fazer isso no VB6.

5-) Você já configurou o linked server entre os dois servidores?

Baseado em suas respostas poderei sugerir algumas alternativas.

O SQL Server possui uma boa ferramenta para realizar integrações entre bases de dados. É o SQL Server Integration Services, se quiser saber mais sobre ele, visite o site do MSDN (http://msdn.microsoft.com/en-us/library/ms141026.aspx).

Aguardo sua resposta!

Abraço!

Rubens disse...

Grande Evandro, Muito Obrigado Mesmo pelo seu Retorno!
Vou responder suas perguntas...

1-) Os dois bancos de dados estão rodando o SQL Server? Em caso afirmativo, rodam a mesma versão?
Resposta: Sim os 2 Bancos vão rodar em SqlServer Sempre na mesma Versão: cenários com Sql2005(para Retaguarda e para o Frente) ou Sql2008(p/ambos também)

2-) A estrutura das tabelas nos dois bancos de dados é a mesma?
Resposta: Não são as mesmas estruturas das tabelas. Nem a mesma quantidade de tabelas que tem num tem no outro.

3-) Os dois bancos precisam estar sincronizados com os mesmos dados? Ou existem registros que só devem existir em um dos bancos?
Resposta: No Sistema Retaguarda terá a base completa da empresa, ou seja, todo o volume de dados gerados pelos computadores que terão os sistemas Frente de Caixa Rodando. Então no Retaguarda terão, alem das movimentações vindas dos sistemas de Frente de caixa, também outros tantos controles financeiros da empresa. Em cada estação que roda o Frente terá uma base local contendo todas as vendas feitas somente ali naquela estação que são jogadas para o Retaguarda em determinado momento que o usuário enviar a carga desses dados. Cada Sistema Frente Caixa receberá do Retaguarda somente as Tabelas de Cadastros a exemplo tabelas de Produtos, de Clientes etc.

4-) Você pretende desenvolver esta solução inteiramente em banco de dados? Ou planeja criar uma aplicação/serviço para desempenhar esta tarefa? Pelo que eu entendi, você está tentando fazer isso no VB6.
Resposta: Estou tentando fazer essa interligação Mista, ou seja, gostaria de disparar via o software Frente de Caixa a execução de Stored Procedures que estarão previamente colocadas em cada Base. Então estabeleço uma conexão via software e passo a enviar os registros de determinada tabela para a Stored Procedure da Base e a cada registro mando executar tal Stored Procedure na Base em que eu estiver alimentando naquele momento.
Pois do Frente enviarei as Vendas e do Frente também IREI Buscar os Cadastros no Retaguarda.

5-) Você já configurou o linked server entre os dois servidores?
Resposta: Pois é, consegui sim estabelecer a conexão usando o ADODB.Connection . Conectou passo dados do registro a ser enviado ou recebido para a SP então dou um VB.EXECUTE e está ocorrendo a tal Atualização entre as 2 Bases.

Não sei é se esse é um Método Viável ao se Deparar com “N” Cenários de máquinas/redes Diferentes. Não sei se é o Método mais rápido ou mais Seguro etc... Estou fazendo pois foi o úncio meio que encontrei por ora...

Já Pesquisei sobre alguns Serviços já presentes no SQL como o RCP e outros o grande inconveniente é que vi em todos seria o meu controle de envio de cada Registro, ou seja, se ocorreu um erro num processo em que eu tivesse enviado o lote, qual registro foi ou qual não foi... Do jeito que estou enviando tenho esse controle, pois só marco o Registro como enviado após não receber Erros na Execução da Procedure alimentada com aquele Registro.

Mais ou menos vou Descrever para você num e-mail que vou lhe enviar como ficou minha Rotina, aqui não coube... rss
Abraço!

Evandro disse...

Olá Rubens,

Não conheço tanto a linguagem VB, nunca trabalhei com ela. Mas, pelo que eu entendi, você está utilizando uma conexão (CNN) para acessar o DBRetaguarda e uma outra conexão (vgDb(2)) para acessar o DBFrente. Estou certo?

Acredito que esta seja a melhor maneira. Talvez não seja a mais eficiente, uma vez que este procedimento requer um no mínimo 2 consultas para cada linha da tabela a ser integrada. Entretanto, a execução via aplicação torna este processo mais controlado, permitindo que sejam aplicadas regras de negócio e validações para tratar cada registro, caso isso seja necessário. Acredito que as regras de negócio devem ser concentradas na aplicação....

Fora isso, tenho algumas recomendações para melhorar o controle da sua aplicação....

1. Costumo sempre utilizar um bloco TRY.. CATCH... FINALLY para fazer acessos a banco de dados. Abrindo a conexão e executando a consulta no bloco TRY, tratando possíveis erros no CATCH e sempre fechando a conexão no FINALLY. Pesquisei na internet e verifiquei que, assim como no C#, essa estrutura também existe no VB (http://msdn.microsoft.com/en-us/library/fk6t46tz%28v=vs.80%29.aspx). Acredito que esta seja uma boa prática e torne o código mais controlado.

2. Evite utilizar o caracter * para fazer consultas em tabelas através de aplicações. Desta forma o código fica muito dependente da estrutura da tabela. A inclusão, exclusão ou simples troca de posição entre colunas da tabela pode impactar na aplicação. Uma boa prática seria a declarar todas as colunas a serem retornadas no comando SELECT. O uso de stored procedures para todos os acessos também é uma prática interessante, pois aumenta a segurança dos acessos.

3. Você pensou em adicionar um controle transacional nesta operação? A transação pode garantir a integridade dos seus dados principalmente por tratar de atualizações em servidores diferentes. Não conheço muito sobre a utilização de transações distribuídas em aplicações, mas, se você tiver interesse, posso pesquisar e podemos aprender juntos como utilizá-las em aplicações .Net.

Abraço!

Mariana Mazzolani disse...

muito bom

Postar um comentário