Quando estamos escrevendo nosso código T-SQL, há aqueles momentos em que desejamos executar a mesma lógica mais de uma vez. Para conseguirmos isso, podemos utilizar a palavra-chave WHILE. Há outros momentos em que desejamos realizar um teste condicional e, dependendo dos resultados do teste de execução de um bloco de código para a condição verdadeira e, possivelmente, um bloco de código diferente quando a condição for falsa. Quando precisamos executar condicionalmente códigos com base no resultado de outra condição, podemos utilizar a palavra-chave IF. Neste artigo, estaremos discutindo como podemos usar o nosso tempo e construir um controlador de fluxo para o nosso código T-SQL.

Sintaxe básica do WHILE

A sintaxe de loop while é bastante simplista, a qual podemos ver de acordo com a Listagem 1.

Listagem 1. Sintaxe básica do loop WHILE.

WHILE Boolean_expression
       { sql_statement | statement_block | BREAK | CONTINUE }

A execução do loop While é controlada com base nos resultados booleanos da expressão Boolean_expression, onde, enquanto essa expressão for avaliada como TRUE, então o bloco de código dentro do loop while será executado e o Boolean_expression será reavaliado numa nova iteração. Uma vez que ele seja falso, o bloco de código não será mais executado. O bloco de código dentro do loop while poderia ser uma única instrução T-SQL ou mesmo, várias instruções agrupadas dentro de um bloco BEGIN ... END. Se quisermos sair programaticamente do loop while sem esperar que a Boolean_expression tenha uma avaliação FALSE, podemos fazer isso utilizando a palavra-chave BREAK. Ou mesmo se quisermos pular o resto do código no loop WHILE e continuarmos o processamento a partir do começo do loop, então podemos usar a palavra-chave CONTINUE. Veremos mais sobre isso no decorrer do artigo.

No decorrer desse artigo iremos realizar alguns testes com base em exemplos simples, onde abordaremos os conceitos básicos e formas de utilizarmos o WHILE a fim de melhorarmos nossos códigos, exemplos estes que começaremos neste momento.

Exemplo simples de utilização do WHILE

Começaremos então por um exemplo de loop simples, onde veremos criaremos uma tabela de números com os números de 1 a 50. Este é o tipo de exemplo que não nos deixa dúvidas, mas é bom de rever para entender o conceito básico do loop. O código presente na Listagem 2 irá então, criar e preencher uma tabela de números usando um loop while simples, fazendo uso da estrutura básica apresentada pela Listagem 1.

Listagem 2. Construção básica do while.

DECLARE @I INT = 0;
  -- criando a tabela que será populada
  CREATE TABLE Numeros (numero Int);
  WHILE @I < 50
  BEGIN
      SET @I += 1;
      INSERT INTO Numeros VALUES (@I);
  END
  SELECT * FROM Numeros;

Primeiramente aqui, declaramos uma variável chamada de I que foi inicializada como 0. Após isso, processamos o loop while, desde que o valor da variável @I seja menor que 50. Informamos desta forma que enquanto o valor da variável for menos que 50, o seu valor será incrementado a esta variável e sendo ele inserido na base de dados. Quando atingimos o nosso limite, o loop é encerrado e podemos ver o nosso resultado na tabela que criamos através da instrução select também presente na Listagem 2. Vamos complicar um pouco mais? Seguindo para a utilização de breaks e continues.

Loop WHILE seguido de instruções BREAK e CONTINUE

Em caso de termos a necessidade de pular condicionalmente algum código no interior do loop WHILE, mas ainda continuar com a próxima iteração, o que podemos fazer é usar a palavra-chave CONTINUE dentro do loop em questão. Além disso, se quisermos realmente sair do loop, podemos fazer isso utilizando a palavra-chave BREAK. Para demonstrarmos então o uso destas palavras-chaves, utilizaremos o código presente na Listagem 2, mas com algumas modificações presentes na Listagem 3.

Listagem 3. Utilização do loop While com palavras-chaves BREAK e CONTINUE.

SET NOCOUNT ON;
  DECLARE @Contador int = 1; 
  DECLARE @I int; 
  SET @I = 0;
  WHILE @I < 50
  BEGIN
      SET @I += 1; 
      SELECT 'Loop 1 Iteração# ' + 
             CAST (@I as char(2)) + 
                                  ' Contador recente = ' + CAST(@Contador as CHAR(2));
      IF @I = 3 
                     CONTINUE;
      IF @I = 5
                     BREAK;
      SET @Contador += 1;
  END

Se analisarmos o código presente na Listagem 3, podemos ver o código executa a palavra-chave CONTINUE quando a variável @I é definida como 3, e a instrução break é utilizada quando a variável @I é definida para 5. Esta variável é então incrementada em 1 a cada loop através do loop WHILE, e o valor de I também é apresentado como sendo "Interação #" em uma instrução SELECT no começo do loop. Além disso, mantivemos o controle do valor com a utilização de um contador que começa em 1 e é incrementado em 1 a cada vez que chega ao final do loop.

A razão pela qual o texto “contador recente = 3” aparece duas vezes na saída do resultado é porque temos aqui uma expressão IF que testa se o @I é igual a 3. Quando expressão é verdadeira, executamos a palavra-chave CONTINUE. Quando essa palavra-chave CONTINUE é executada, todo o código presente no loop WHILE que está abaixo desta palavra-chave é ignorado e a execução começa na primeira declaração do loop WHILE novamente. Portanto, quando a palavra-chave CONTINUE é executada, a instrução SET na parte inferior do loop while não é executado e, portanto, a variável Contador não será definida para o próximo valor sequencial. Além disso, a razão pela qual a última "Iteração #" é 5, este caso é devido a uma vez que o valor da variável @I é 5, a instrução break é executada e então o processo é encerrado.

Aninhamento com loops while

O loop WHILE também pode ser aninhado, assim como os if’s. Para demonstrarmos este exemplo, modificaremos o código presente na Listagem 3 para que tenhamos um outro loop while. Esse novo código deverá ser parecido com o apresentado pela Listagem 4.

Listagem 4. Aninhamentos com While.

SET NOCOUNT ON;
  DECLARE @Contador int = 1;
  DECLARE @Interno int;
  DECLARE @Externo int = 0;
  WHILE @Externo < 2 
  BEGIN 
      SET @Externo +=1; 
      SET @Interno = 0;
      SET @Contador = 1;
      WHILE @Interno < 10
      BEGIN
                     SET @Interno += 1; 
                     SELECT 'Externo Loop Iteração# ' + 
                                                  CAST(@Externo as char(2)) + 
                                                  'Interno Loop Iteração# ' + 
                                      CAST (@Interno as char(2)) + 
                                                 ' Valor do número corrente = ' + CAST(@Contador as CHAR(2));
                     IF @Interno = 3 
                                   CONTINUE;
                     IF @Interno = 5
                                   BREAK;
                     SET @Contador +=1;
      END
      SELECT 'Fim do loop interno';
  END 
  SELECT ' Fim do loop Externo';

Se vocês analisarem o código presente na Listagem 4, vocês poderão perceber que fechamos o loop da Listagem 3 no interior de um outro loop while, no caso, o loop while externo. Este novo loop WHILE será referido como sendo o nosso laço externo, enquanto que o loop while original Listagem 3 será chamado de loop interno. Nós os chamaremos dessa forma, de exterior e interior, apenas para refletirmos o nível de aninhamento existente aqui. Dessa forma, temos que o loop interno está aninhado dentro do externo. Uma outra diferença aqui no nosso exemplo foi que renomeamos os loops para interno e externo apenas para que saibamos melhor do nosso controle. Ao rodarmos o exemplo, a mensagem que nos serão exibidas, serão os valores das variáveis que controlam tanto o loop interno e quanto o externo.

Sintaxe de construção IF

Saindo agora do WHILE, vamos ver mais uma forma de condicional que também é bastante comum em nossos códigos, que é a condicional IF. Em determinados momentos no decorrer do nosso código, desejamos executar algum código adicional ou mesmo alternativo com base na avaliação de uma expressão. Isto é, quando uma lógica IF vem para nos socorrer. Vocês já devem ter notado que usamos aqui a palavra-chave IF em sua forma mais simples, presente nas Listagens 3 e 4 acima. Ao analisarmos a sintaxe do IF, podemos ver essa sintaxe de duas formas, como apresentaremos através da Listagem 5.

Listagem 5. Sintaxe básica do IF.

IF Boolean_expression 
       { sql_statement | statement_block } 
  [ ELSE 
       { sql_statement | statement_block } ]

Uma das formas de se utilizar o IF seguido de sua Boolean_expression sendo retornada como verdadeira, onde neste caso, temos apenas um bloco de instruções onde passamos a lógica necessária e verificamos a sua veracidade. E o segundo momento é quando temos os dois blocos condicionais, sendo o primeiro IF acompanhado da expressão Boolean_expression como verdadeira, e em caso de seu resultado ser falso, o resultado passa a ser obtido pelo segundo bloco da condição, que é o ELSE, onde nos dará a resposta alternativa para quando a expressão não for retornada como Verdadeira.

Assim como o WHILE, podemos também criar IF’s aninhados, de forma que não há um limite para o número de níveis de aninhamento que possamos usar. Para que possamos obter uma melhor compreensão dos diferentes formatos de IF, construiremos mais alguns exemplos com base da sua sintaxe básica.

Exemplos de utilização da condicional IF

Para darmos continuidade ao nosso primeiro exemplo usando o IF, vamos olhar para uma simples instrução IF que realiza um teste no valor de uma variável local. O código que será utilizado para o nosso exemplo será de acordo com o apresentado pela Listagem 6.

Listagem 6. Teste de valor de uma variável local com a condicional IF.

DECLARE @I INT = 1;
  IF @I = 1
      PRINT '@I = 1';
  PRINT 'Agora tá feito!';

Bastante simples! Aqui podemos ver que quando o nosso Boolean_expression é avaliado pelo IF como sendo TRUE, o que significa que a variável local @I for igual a 1, a instrução PRINT que segue o Boolean_expression foi executado. Além disso, a última declaração de impressão na lista também foi executada. Se definirmos a variável @I na Listagem 6 para um valor diferente de 1, e em seguida, executarmos o código, veremos que teremos apenas a mensagem “Agora tá feito” sendo impressa.

Se precisarmos executar várias instruções SQL quando o Boolean_expression for verdadeiro, podemos fazer isso através da inclusão de um grupo de instruções T-SQL em um bloco BEGIN..END. E como nosso próximo exemplo, veremos esta implementação de acordo com o apresentado através da Listagem 7.

Listagem 7. Bloco de instruções Begin..End na condicional IF.

DECLARE @I int = 1;
  IF @I = 1
  BEGIN
      PRINT 'Esta instrução será executada apenas quando... ';
      PRINT 'a variável for igual a 1';
  END

Quando executarmos este código presente na Listagem 7, ambos as informações (os prints) serão executados apenas quando a variável @I for igual a 1. De qualquer forma, em determinados momentos precisamos executar dois blocos de código diferentes dependendo do resultado do Boolean_expression. Isto é, quando a lógica da construção ELSE IF é de grande importância. O código presente na Listagem 8 nos mostra como devemos usar a palavra-chave IF em conjunto com a cláusula ELSE para obtermos este resultado. Neste exemplo vamos criar uma lógica simples que nos informará quando o número será par ou ímpar.

Listagem 8. Verificando se um número é par ou ímpar.

DECLARE @I INT = 0;
  WHILE @I < 30 
  BEGIN 
      IF @I%2 = 0
                     PRINT ' O número ' + CAST(@I AS char(1)) + ' é um número par.'
      ELSE 
                     PRINT ' O número ' + CAST(@I AS char(1)) + ' é um número ímpar.'
      SET @I += 1;
  END

Ao analisarmos o código presente na Listagem 8, podemos ver que usamos aqui um loop WHILE que está sendo controlado pela variável @I, permitindo testar a nossa expressão IF com diferentes valores de I. Cada vez que o loop WHILE é executado, a condição IF é usada para testar se a variável @I é um número ÍMPAR ou um número PAR. Se o Boolean_expression for avaliado como TRUE, imprimiremos uma mensagem informando que o módulo do valor da variável é divisível por 2 e por conseguinte, o número é par. Em caso contrário, se o Boolean_expression for definido como FALSE, então a cláusula ELSE será executada, o que imprimirá uma mensagem de que o valor da variável é ÍMPAR. Seguiremos agora para um outro tipo de exemplo onde iremos utilizar uma estrutura aninhada, veremos então de acordo com a Listagem 9 a sua implementação.

Listagem 9. Utilização de estruturas aninhadas.

DECLARE @I INT = 0;
  WHILE @I < 30 
  BEGIN 
    IF @I%2 = 0
      IF TAN(@I) > 0
        PRINT ' O valor ' + CAST(@I as char(1)) + ' é Ímpar e a tangente é maior que zero'
      ELSE
        PRINT 'O valor ' + CAST(@I as char(1)) + ' é ímpar e a sua tangente é menor ou igual a zero.'  
      ELSE 
        IF TAN(@I) > 0
           PRINT ' O valor ' + CAST(@I as char(1)) + ' é par e a tangente é maior que zero.'
        ELSE
           PRINT PRINT ' O valor ' + CAST(@I as char(1)) + ' é par e a tangente é menor ou igual que zero.'  
      SET @I += 1;
  END

Agora que estamos analisando o código presente na Listagem 9, veremos aqui que temos um loop while, de igual forma ao presente na Listagem 8, que possui um bloco BEGIN..END e em seu interior um aninhamento IF..ELSE que definirá se o valor da variável @I é do tipo par ou ímpar e também testamos neste mesmo exemplo com relação aos resultados da expressão "TAN (I)" se são maiores ou menores que zero. Dependendo dos resultados dos dois IF’s, as condições para a Boolean_expression, serão exibidas mensagens diferentes que irão utilizar diferentes declarações de impressão.

Agora para finalizarmos, criaremos um exemplo utilizando todo o conceito aprendido aqui que irá utilizar a base de dados AdventureWorks2012 e executaremos diferentes instruções, contudo, levando-se em consideração tudo que foi apresentado aqui. Faremos então o nosso teste com o código que está presente na Listagem 10.

Listagem 10. Exemplo final utilizando a base de dados AdventureWorks2012.

USE AdventureWorks2012;
  GO
  DECLARE @PesoMedio decimal(8,2), @Contador int
  IF 
  (SELECT COUNT(*) FROM Production.Product WHERE Name LIKE 'Touring-3000%' ) > 5
  BEGIN
     SET @Contador = 
          (SELECT COUNT(*) 
           FROM Production.Product 
           WHERE Name LIKE 'Touring%');
     SET @PesoMedio = 
          (SELECT AVG(Weight) 
           FROM Production.Product 
           WHERE Name LIKE 'Touring%');
     PRINT 'Existem em torno de ' + CAST(@Contador AS varchar(3)) + ' bicicletas Touring.'
     PRINT 'O peso médio das bicicletas no top 5 Touring é ' + CAST(@PesoMedio AS varchar(8)) + '.';
  END
  ELSE 
  BEGIN
  SET @PesoMedio = 
          (SELECT AVG(Weight)
           FROM Production.Product 
           WHERE Name LIKE 'Touring%' );
     PRINT 'O peso médio das bicicletas Touring é ' + CAST(@PesoMedio AS varchar(8)) + '.' ;
  END ;
  GO

Aqui verificamos então de igual forma ao exemplo da Listagem 9, fazendo uso de blocos BEGIN..END e usando uma condicional para que a partir do resultado de um select tenhamos as informações referentes a quantidade de itens de um determinado tipo de produto e também tenhamos o peso médio que tenham esses produtos. Este é o tipo de exemplo real que podemos encontrar em nossas pesquisas e trabalhos daqui pra frente.

Vimos então neste artigo sobre a utilização de Loops WHILE e expressões IF. Vimos como utilizá-los de uma forma simples, mas com a intenção maior de darmos a ideia de como utilizá-las em casos reais (como pode ser com exemplo do valor ímpar ou par). Enfim, se precisarmos controlar o fluxo de nosso código T-SQL para que executemos um bloco de código várias vezes específicas, devemos considerar o uso de um loop WHILE. Se quisermos executar condicionalmente códigos com base em uma condição ser verdadeira ou falsa, devemos considerar o uso de uma instrução IF. A construção WHILE nos fornece um mecanismo de loop dentro do código T-SQL. Como vimos, esse código pode ser ter uma única instrução ou ser repetido num bloco de instruções. A construção IF fornece um mecanismo para executarmos uma única instrução T-SQL, ou mesmo um bloco de instruções T-SQL com base no valor de uma expressão booleana. Sabendo de tudo isso, na próxima vez que vocês precisarem controlar o fluxo de seu código T-SQL, possivelmente irão considerar uma redução de tempo de trabalho e o auxílio dos IF’s e dos WHILE’S como aliados importantes. Até a próxima!