DevMedia
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login

Banco de Dados Firebird: IF-THEN-ELSE, BEGIN-END e Comentários

Aprenda nesse artigo como o banco de dados lida com certas estruturas de decisão, de iteração e veja também como analisar o funcionamento dos agrupamentos, a criação e manutenção de blocos de código em instruções, loops, etc.

[fechar]

Você não gostou da qualidade deste conteúdo?

(opcional) Você poderia comentar o que não lhe agradou?

Confirmo meu voto negativo

Qualquer desenvolvedor e/ou usuário de bando de dados, mesmo os que tem pouca experiência com os mesmos, sabe que o SQL é sua linguagem básica e fundamental e que o mesmo é regido por comandos e por algumas estruturas básicas de lógica de programação, tais quais as que vemos em linguagens famosas, como o Java ou o Delphi. Trabalhar com bancos de dados é uma tarefa relativamente simples, mas exige algumas capacidades como memorização (dos comandos, das estruturas, etc), associação (para entender como funcionam relacionamentos, formas normais, etc) e raciocínio lógico (para criar estruturas lógicas flexíveis e adaptáveis aos diferentes modelos de negócio). E nesta última capacidade que iremos trabalhar nesse artigo.

Trataremos de entender aqui não somente como o banco de dados lida com certas estruturas de decisão, de iteração, etc., mas também analisar como funcionam os agrupamentos, a criação e manutenção de blocos de código em instruções, loops, etc. tudo encapsulado nas famosas estruturas de Stored Procedures e Triggers. E para essa experiência estaremos usando o banco de dados Firebird, por razões de maturidade e documentação da tecnologia (vide seção Links para encontrar a documentação oficial do Firebird).

A linguagem das Stored Procedures e Triggers, por sua vez, é uma linguagem criada para “ser executada em um banco de dados”, literalmente. Por esta razão, a sua atuação é limitada às operações de base de dados e às funções necessárias; já a PSQL é, em si, contudo, uma linguagem poderosa, e oferece mais funcionalidades do que você pode usar. Você pode encontrar uma gama completa de palavras-chave e funções disponíveis para uso em procedures e triggers na seção Links, e para não estender demais o artigo, vamos nos ater às funções e recursos mais básicos como forma de introdução.

Stored Procedures

O Firebird utiliza stored procedures (ou procedimentos) como ambiente de programação para a integração de processos ativos no banco de dados.

Existem dois tipos de procedimento armazenado: executável e selecionável. Um procedimento executável retorna não mais do que um conjunto de variáveis. Um procedimento de seleção pode, usando a palavra-chave SUSPEND, recuperar variáveis, um conjunto de dados por vez. Se uma instrução EXECUTE PROCEDURE contém um SUSPEND, então SUSPEND tem o mesmo efeito que EXIT. Este uso é legal, mas não é recomendável, e infelizmente é um erro que mesmo os programadores mais experientes costumam cometer.

A sintaxe para declarar os dois tipos de procedures é a mesma, mas existem duas maneiras de invocá-la ou chamá-la: uma procedure pode agir como um procedimento funcional em outra linguagem, da mesma forma que você pode executá-la e ela lhe dar uma resposta ou nenhuma resposta. Veja o código a seguir para tal:

execute procedure <nome_da_procedure>

A outra maneira mais básica de fazer isso é criar uma procedure como se você estivesse fazendo uma consulta básica a uma tabela:

select * from <nome_da_procedure>

Dessa forma, você pode recuperar os dados retornados como uma subtabela em forma de resposta.

Vamos analisar então o código contido na Listagem 1.

Listagem 1. Exemplo de procedure básica com SUSPEND

CREATE PROCEDURE ANIMAL
   RETURNS (TEXTO VARCHAR(25))
   AS
   BEGIN
     TEXTO='ARARA';
     SUSPEND;
     TEXTO='BALEIA';
     SUSPEND;
     TEXTO='TIGRE';
     SUSPEND;
   END

Esse é um exemplo bem simples de uma procedure que se comporta como uma tabela, usando o SUSPEND para fornecer os retornos e funcionando como um RETURN de linguagens comuns. Nela, a variável de retorno é TEXTO. O valor “ARARA” é inserido e, especificando o SUSPEND, o servidor envia o resultado ARARA no buffer para uma pilha de resultados.

Quando o próximo conjunto de dados está escrito, ele é empurrado para a pilha de resultado. Ao usar o SUSPEND em uma procedure, é possível a definição de dados que não seria possível em um SQL. É uma ajuda extremamente poderosa, principalmente para a geração de relatórios.

Além disso, note que no exemplo também fazemos uso da estrutura BEGIN-END, extremamente conhecida por desenvolvedores Pascal, por exemplo, por ser uma estrutura muito semelhante à forma como a linguagem lida com blocos de código. Tal como no Pascal, o BEGIN-END serve para delimitar o agrupamento de uma instrução, seja ela uma condição, um loop, etc. A sintaxe é bem simples e é uma instrução que permite aninhamentos, isto é, podemos ter BEGIN-END dentro de outros BEGIN-END’s.

Você pode executar suas procedures diretamente no console SQL da sua ferramenta SGBD ou utilizar alguma ferramenta gráfica para isso, como a IBPhoenix (Figura 1).

Exemplo de execução de
procedures via opção gráfica

Figura 1. Exemplo de execução de procedures via opção gráfica

Triggers

Uma trigger (ou gatilho), por outro lado, é um procedimento ligado de tabelas ou base de dados especial, que é iniciado automaticamente. Depois de criar o seu banco de dados e construir a estrutura da tabela, você precisa ter as suas triggers ordenadas. As triggers são extremamente poderosas - o chamado serviço de polícia do banco de dados. Eles garantir a integridade do banco de dados, porque você simplesmente não pode escapar delas.

O desenvolvedor, diz ao sistema como invocá-las e se elas devem reagir a um INSERT, UPDATE e/ou DELETE. E uma vez que já estivermos inserindo, atualizando ou excluindo, é impossível parar de executá-los. Você pode especificar se o gatilho deve disparar sobre uma inserção ou uma atualização ou um DELETE, ou em todas as três ações (trigger universal). A Listagem 2 representa um exemplo simples e básico de como criar uma trigger.

Listagem 2. Exemplo básico de criação de trigger

CREATE EXCEPTION TEXTOERRO 'ERRO';   CREATE PROCEDURE criarautoinc
   AS
   declare variable sql_exemplo varchar(500);
   declare variable tabela varchaR(30);
   BEGIN
     FOR
       select rdb$relation_name from rdb$relations r
       where r.rdb$relation_name not containing '
       INTO :tabela
     DO
     BEGIN
        sql_exemplo='CREATE trigger '||:tabela||'_bi0 for '||:tabela||' '||
            'active before insert position 0 AS '||
            'BEGIN '||
            '  if (new.id is null) then '||
            '  new.id = gen_id(id, 1); '||
            'END';
         execute statement :sql_exemplo;
     END
     when any do exception textoerro :tabela;
   END

Perceba que no exemplo estamos usando todos os nomes de tabelas (os quais estão guardados em rdb$relations) e criando uma trigger BEFORE INSERT, que irá adicionar um identificador auto incremento. Note também que estamos fazendo uma chamada direta à prodecure “criarautoinc”, como mostra a Listagem 3, que retrata a forma como essas duas estruturas andam juntas, as triggers precisando mais das procedures do que o contrário.

Listagem 3. Prodecure “criarautoinc” para uso na trigger

-- Procedure principal que irá auto incrementar  
CREATE PROCEDURE criarautoinc
   AS
   declare variable sql_exemplo varchar(500);
   declare variable tabela varchaR(30);
   BEGIN
     FOR
       select rdb$relation_name from rdb$relations r
       where r.rdb$relation_name not containing '
       INTO :tabela
     DO
     BEGIN
        sql_exemplo='DROP trigger '||:tabela||'_bi0;';
        execute statement :sql_exemplo;
     END
     when any do exception textoerro :tabela;
   END

Comentários

Os comentários, assim como nas queries SQL básicas, também são permitidos nas procedures e triggers, cuja sintaxe depende de cada bando usado.Em se tratando do Firebird, os comentários podem ser apresentados de duas formas:

  • através do uso dos operadores /* ... */ para comentários de mais de uma linha, como mostra o código a seguir:
    /*Apresentando a Procedure principal 
                  que irá auto incrementar*/  
  • ou através do uso de dois traços (--) para comentários de uma linha só, como vimos na primeira linha da Listagem 3.

Declarações Condicionais

IF...THEN...ELSE

Assim como nas linguagens de programação, as estruturas condicionais IF...THEN...ELSE servem para estabelecer condições no fluxo de execução do código. Se a expressão de teste de uma instrução IF for NULL, a cláusula, então, é ignorada e a cláusula ELSE, se houver, é executada. Em outras palavras, NULL e falso tem o mesmo efeito no presente contexto.

Por essa razão, podemos ter desde a simples execução de um teste condicional com operadores de “maior que“ ou “menor ou igual que”, até estruturas de comparação entre variáveis criadas pela procedure ou trigger em questão. Vejamos o código da Listagem 4 para um exemplo disso.

Listagem 4. Exemplo de condições no Firebird

if (a > 18) then
       resultado = ‘Maior de idade’;
  else
       resultado = ‘Menor de idade’;
   
  -- ou...
   
  if (varA = varB) then
    minhaVar = 'Iguais';
  else
    minhaVar = 'Não iguais';

Se uma das duas variáveis varA ou varB forem nulas, então o valor da variável minhaVar continuará sendo “Não iguais”, o que comprova nossa afirmativa anterior. Você pode encontrar uma lista completa dos operadores e mais exemplos condicionais no site oficial do Firebird.

Além disso, temos diversas outras variações que podem ser utilizadas com o bloco IF-THEN-ELSE. Veja algumas delas:


  • Valor LIKE valor: O valor à direita pode incluir um ou mais curingas. Use % para zero ou mais caracteres e _ para um caractere;
  • Valor IN (valor1, valor2, valor3, &): Membro de uma lista de valores;
  • Valor EXISTS (subquery): Verdadeiro se o valor combinar com um dos valores retornados pela subquery;
  • Valor ANY (subquery): Verdadeiro se o valor combinar com qualquer das linhas retornadas pela subquery;
  • Valor ALL (subquery): Verdadeiro se o valor combinar com todas as linhas retornadas pela subquery;
  • Valor IS NULL: Verdadeiro se o valor for nulo;
  • Valor IS NOT NULL: Verdadeiro se o valor não for nulo;
  • Valor CONTAINING valor: Busca de substring sem diferenciar maiúsculas e minúsculas;
  • Valor STARTING WITH valor: Verdadeiro se o valor a esquerda iniciar com o valor a direita. Diferencia maiúsculas e minúsculas.

CASE

O Firebird introduziu a construção CASE na versão 1.5, com duas variantes sintáticas. O primeiro é chamado de “sintaxe simples”, como mostra a Listagem 5.

Listagem 5. Estrutura da condição Case

case <expressao>
    when <exp1> then <resultado1>
    when <exp2> then <resultado2>
    ...
    [else <resultadopadrao>]
  end

Essa também é uma estrutura extremamente semelhante à apresentada nas linguagens de programação e serve, basicamente, para determinar quando uma condição ou expressão deve ser atendida, não se atendo somente a valores inteiros ou chars, por exemplo. A segunda variante, também conhecida como “sintaxe de pesquisa” pode ser visualizada a Listagem 6.

Listagem 6. Sintaxe de pesquisa do case

case
    when <condição1> then <resultado1>
    when <condição2> then <resultado2>
    ...
    [else <resultadopadrao>]
  end

Aqui, as são testes que dão um resultado boolean ternário: verdadeiro, falso, ou NULL. Mais uma vez, só TRUE é bom o suficiente, por isso, uma condição como "A = 3" - ou mesmo "A = null" - não é satisfeita quando A é NULL.

Estruturas de Repetição

WHILE

A estrutura também se equipara às das linguagens de programação e funciona basicamente recebendo a condição e executando o bloco de código caso a mesma seja verdadeira. Ao avaliar a condição de um loop while, o NULL tem o mesmo efeito que em uma instrução IF: se a condição resolve para NULL, o laço não é (re)entrada – da mesma forma como se fosse falsa. Mais uma vez, cuidado com inversão usando NOT: uma condição como:

while ( contador > 10 ) do

irá ignorar o bloco loop se a variável “contador” for NULL, que é provavelmente o que você quer. Mas:

      while ( not contador > 10 ) do

também vai saltar se o “contador” for NULL. Talvez isso também seja exatamente o que você quer, mas esteja ciente de que esses testes aparentemente complementares ambos excluem contadores nulos.

FOR

Para evitar qualquer confusão possível, vamos enfatizar aqui que loops FOR no Firebird PSQL tem uma função totalmente diferente do que os loops WHILE, ou loops em linguagens de programação em geral. Os loops FOR do Firebird têm a seguinte forma sintáxica:

for <declaraçao-do-select> into <lista-var> do <bloqueio-codigo>

e eles vão continuar a execução do bloco de código até que todas as linhas do conjunto de resultados forem recuperadas, a menos que ocorra uma exceção ou uma pausa, termine ou instrução EXIT seja encontrada. Encontrando um NULL, ou até mesmo tendo fila após fila preenchidas com valores nulos, não irá encerrar o ciclo.

Contudo, existem muitas outras funcionalidades, recursos e comandos para se trabalhar com Stored Procedures e Triggers no Firebird, e não se limitam apenas a um único artigo. Veja na seção Links alguns cursos bem completos sobre o assunto que podem te auxiliar a maximizar seus conhecimentos no assunto.

Bons estudos!

Links



Diogo Souza trabalha como Analista de Sistemas Java na Fulcrum WW e já trabalhou em empresas como Instituto Atlântico e Ebix L.A. É instrutor Android, palestrante em eventos sobre Java e o mundo mobile e consultor DevMedia. Conhec [...]

O que você achou deste post?
Conhece a assinatura MVP?
Serviços

Mais posts