Atenção: esse artigo tem um vídeo complementar. Clique e assista!
Este artigo procura apresentar o que são
e como funcionam stored procedures. Para isto, será demonstrado como este
recurso pode ser empregado em uma aplicação que utilize o SQL Server,
utilizando classes de acesso a dados disponibilizadas pela plataforma .NET, por
exemplo, a SqlConnection, para estabelecer uma conexão. Stored procedures ou procedimentos
armazenados são conjuntos de instruções empregados na manipulação de informações
presentes em bancos relacionais. Este tipo de recurso apresenta uma série de
vantagens, entre elas, performance, já que permite que operações realizadas com
frequência fiquem armazenadas e centralizadas na base de dados. Em
que situação o tema é útil Stored procedures podem ser úteis em cenários que exijam uma
maior performance no processamento de operações complexas, envolvendo bancos
relacionais, permitindo inclusive uma redução no tráfego de rede (devido à
lógica de processamento ficar centralizada dentro da própria base). Outra
situação é aquela nas quais restrições de segurança impedem o acesso direto a
determinados recursos de um banco de dados ou até mesmo, uma série de
precauções precise ser tomada para evitar ataques à estrutura e às informações
de uma base de dados. Stored Procedures –
Aprenda a criar procedimentos armazenados Bancos relacionais
representam, sem sombra de dúvidas, o principal meio existente nos dias atuais
para o armazenamento de informações em aplicações de software corporativas.
Durante a construção e/ou a manutenção de soluções que consumam recursos de
bases de dados em inúmeras situações, a linguagem SQL mostrará suas limitações,
já que a mesma não conta nativamente com estruturas que são comuns às
linguagens de programação convencionais, tais como desvios condicionais e laços
de repetição. Stored procedures procuram oferecer uma resposta a tais
necessidades, sendo normalmente implementadas via extensões disponibilizadas
por fornecedores de bancos de dados relacionais.
A realização de operações de consultas ou mesmo, visando à manutenção de informações (inclusão, alteração e exclusão) em bases de dados relacionais é realizada, basicamente, por meio de instruções escritas em SQL (Structured Query Language). Embora a mesma apresente certa padronização, é bastante comum que diferentes bancos de dados contem com uma série de customizações específicas. Um exemplo é a própria criação de stored procedures, onde cada database possui uma implementação especifica.
Nem sempre é possível utilizar somente comandos SQL em consultas a banco de dados. Muita vezes seu uso é insuficiente, haja visto a inexistência dentro desta linguagem recursos convencionais de programação como loopings e desvios condicionais. Atentos a isto, os fornecedores de bancos de dados criaram mecanismos que suprem tais deficiências. No caso do SQL Server, a Microsoft disponibilizou o T-SQL (Transact-SQL); já a Oracle oferece em seus produtos a linguagem PL/SQL (Procedural Language/Structured Query Language).
T-SQL e PL/SQL nada mais são do que extensões procedurais à linguagem SQL. Em ambos os casos, comandos para controle de fluxo e desvios condicionais foram adicionados aos bancos de dados em questão, possibilitando que as limitações do conjunto de instruções SQL padrão fossem superados. Esses recursos representam também a base para a implementação de outros tipos de elementos comuns a bancos de dados relacionais:
• Stored procedures: rotinas criadas dentro de um banco de dados para a execução de uma série de instruções;
• Functions (funções): retornam um valor como resultado do seu processamento, com um comportamento similar ao das funções presentes em linguagens de programação;
• Triggers (gatilhos): conjunto de ações disparadas em resposta a algum evento que ocorra na base de dados, por exemplo, o evento insert.
Embora seja inegável a flexibilidade decorrente do uso de extensões como T-SQL e PL/SQL na resolução de demandas complexas, desenvolvedores devem sempre entender que estes recursos não dispõem de nenhuma forma de padronização. Um conjunto de instruções escrito em T-SQL difere em muito do equivalente em PL/SQL, visto que em cada banco de dados foi empregada uma sintaxe específica.
Todas estas características podem se traduzir numa série de empecilhos. Um exemplo disto é um cenário no qual uma aplicação que foi desenvolvida inicialmente em um tipo de banco e que, pelos mais variados motivos, necessite ter suas informações migradas para um produto de outro fornecedor: estruturas como stored procedures, triggers e functions precisarão ser convertidas para a sintaxe reconhecida pelo novo banco de dados a ser empregado.
A plataforma .NET dispõe de um numeroso conjunto de recursos(por exemplo, acesso a arquivos de textos, xml etc) para tarefas relacionadas ao acesso a dados: trata-se da tecnologia ADO.NET (ActiveX Data Object for .NET), a qual é suportada pelos principais bancos relacionais da atualidade. A maneira através da qual o ADO.NET foi projetado permite a construção, sem maiores dificuldades, de soluções que consumam informações dos mais variados tipos de bases de dados; os principais fornecedores destas ferramentas costumam disponibilizar drivers específicos para acesso a seus produtos. Esses drivers são encontrados diretamente no site da fabricante de seus devidos banco de dados.
Ao considerar bancos relacionais
gerados a partir do SQL Server, é possível também que stored procedures sejam
criadas a partir de classes implementadas por meio da plataforma .NET
(utilizando a sintaxe da linguagem C#, por exemplo). O mesmo procedimento é possível com bancos de
dados Oracle, utilizando estruturas elaboradas em Java. Firebird, DB2 e MySQL são
outros exemplos de bancos de dados que contam com extensões para a escrita de elementos
como stored procedures e triggers.
Stored Procedures em Transact-SQL: uma visão geral
Ao utilizar o Transact-SQL você tem a possibilidade de utilizar mecanismos típicos de linguagens estruturadas na manipulação de informações que constem em bases de dados:
• Declarações de variáveis, as quais podem ser empregadas no tratamento de dados em um conjunto de instruções através da atribuição de valores às mesmas;
• Comandos utilizados para o controle do fluxo quando da execução de uma operação, por meio de construções como desvios condicionais e laços de repetição (loopings); Um exemplo é quando você deseja “varrer” uma consulta e encontrar um valor especifico.
• Recursos para o tratamento de exceções que tenham ocorrido ao longo de um agrupamento de comandos. Na prática, se você esperava por um valor inteiro (por exemplo, idade de uma pessoa) e o mesmo retornou null, seria possível tratar esta exceção para não haver um erro no retorno de uma consulta.
Ao declarar uma variável será necessário especificar o tipo de dado que será armazenado pela mesma. A Tabela 1 lista os principais tipos de dados que podem ser utilizado na definição de novas variáveis.
Tipo de Dado |
Descrição |
CHAR |
Texto com comprimento fixo. |
VARCHAR |
Texto de comprimento variável. |
DATETIME |
Representação de data/hora. |
INT |
Representação de números inteiros, ou seja, sem casas decimais. |
DECIMAL |
Valores numéricos com casas decimais. |
Tabela 1. Alguns tipos de dados que podem ser utilizados em T-SQL para declarar variáveis
A Listagem 1 apresenta um de trecho de código em T-SQL. Neste exemplo podem ser observadas as seguintes instruções:
• A especificação de uma variável de nome @ANO_ATUAL. Variáveis são definidas através do comando DECLARE, sendo que obrigatoriamente devem ser iniciadas pelo caractere “@” (arroba), além de possuir um tipo de dados associado à mesma (neste caso, optou-se por INT, já que a variável em questão receberá um número inteiro);
• O valor correspondente ao ano atual sendo atribuído à variável @ANO_ATUAL, através do uso das funções GETDATE e YEAR (a primeira retorna a data atual e a segunda utiliza o valor devolvido por GETDATE para produzir como resultado um número inteiro que corresponde ao ano corrente). Uma das maneiras de atribuir valores a variáveis dentro de T-SQL é por meio da instrução SET. À esquerda do sinal de igual (“=”) deve estar uma variável com uma expressão à direita deste símbolo, produzindo como resultado um valor do mesmo tipo de dado esperado por tal variável;
• Um desvio condicional representado pelo comando IF/ELSE. Assim como acontece em outras linguagens de programação, esta instrução avalia uma condição booleana: a checagem do resto da divisão do valor associado a @ANO_ATUAL por quatro (por meio do operador de módulo “%”), a fim de determinar se o ano considerado é bissexto;
• Caso a condição avaliada pela cláusula IF seja verdadeira (resto igual à zero), o comando PRINT existente dentro do bloco BEGIN/END é executado. Esta instrução recebe como parâmetro uma string (obtida via concatenação da variável @ANO_ATUAL para o tipo CHAR(4), juntamente com o texto “ é um ano bissexto.”), gerando como resultado uma mensagem em um dispositivo de saída (ao disparar este conjunto de operações a partir do SQL Server Management Studio, a indicação de que o ano atual é bissexto é apresentada na seção Message de uma janela para execução de comandos);
• Se a condição presente na instrução IF for falsa, o bloco que segue ao comando ELSE é acionado (no exemplo, será usada a função PRINT para exibir em tela uma mensagem de que o ano atual não é bissexto).
É possível notar ainda neste primeiro exemplo comentários de dois tipos:
• Em uma única linha, sendo iniciados pelo conjunto de caracteres “--” (sinal de “menos” duas vezes);
• Estendendo por várias linhas, começando pela sequência de caracteres “/*” (“barra” e “asterisco”) e sendo terminados por “*/” (“asterisco” e “barra”).