Translate

quinta-feira, 27 de março de 2014

COMPARAÇÃO DE VALORES NULOS

Uma situação que é muito comum em "enganar" programadores, principalmente os que estão começando em PL/SQL é a comparação com valores NULL.

Vamos verificar alguns exemplos abaixo: 

declare

  v_valor1 varchar2(10):= null;
  v_valor2 varchar2(10):= '10';
  
  begin
    
    -- Caso 1 
    if v_valor1 = v_valor2 then
      dbms_output.put_line('Caso 1 - Valor '|| v_valor1||' é igual a '||v_valor2);
    else
      dbms_output.put_line('Caso 1 - Valor '|| v_valor1||' é diferente de '||v_valor2);
    end if;
    
    -- Caso 2
    if v_valor1 != v_valor2 then
      dbms_output.put_line('Caso 2 - Valor '|| v_valor1||' é diferente de '||v_valor2);
    else
      dbms_output.put_line('Caso 2 - Valor '|| v_valor1||' é igual a '||v_valor2);
    end if; 
    
    -- Caso 3
    if nvl(v_valor1,-1) != nvl(v_valor2,-1) then
      dbms_output.put_line('Caso 3 - Valor '|| v_valor1||' é diferente de '||v_valor2);
    else
      dbms_output.put_line('Caso 3 - Valor '|| v_valor1||' é igual a '||v_valor2);
    end if;
    
    -- Caso 4
    if v_valor1 like v_valor2 then
      dbms_output.put_line('Caso 4 - Valor '|| v_valor1||' é igual de '||v_valor2);  
    else
      dbms_output.put_line('Caso 4 - Valor '|| v_valor1||' é diferente a '||v_valor2); 
    end if;   
    
    -- Caso 5
    if v_valor1 not like v_valor2 then
      dbms_output.put_line('Caso 5 - Valor '|| v_valor1||' é diferente de '||v_valor2);
    else
      dbms_output.put_line('Caso 5 - Valor '|| v_valor1||' é igual a '||v_valor2);
    end if;
    
      -- Caso 6
    if nvl(v_valor1,-1) not like nvl(v_valor2,-1) then
      dbms_output.put_line('Caso 6 - Valor '|| v_valor1||' é diferente de '||v_valor2);
    else
      dbms_output.put_line('Caso 6 - Valor '|| v_valor1||' é igual a '||v_valor2);
    end if;  
    
  end;
  
Caso 1 - Valor  é diferente a 10
Caso 2 - Valor  é igual a 10
Caso 3 - Valor  é diferente a 10
Caso 4 - Valor  é diferente a 10
Caso 5 - Valor  é igual a 10
Caso 6 - Valor  é diferente a 10


No caso 1, usando operador "=", o resultado está correto, nulo é diferente de 10.
No caso 2, usando operador "!=",o resultado está incorreto, nulo não é igual a 10.
No caso 3, para corrigir o caso 2, utilizamos um NVL, adicionando um valor qualquer para o valor nulo, trazendo a resposta correta.
Quando usamos o NVL, o campo deixa de ser nulo e então o Oracle compara um valor existente com outro valor existente, porém é preciso tomar cuidado com
essa prática, o que falarei mais abaixo.
No caso 4, usando operador like, o resultado está correto, nulo é diferente de 10.
No caso 5, usando operador not like, o resultado está incorreto, nulo não é igua a 10
No caso 6, usando operador not like com NVL,  o resultado está correto.


Devemos ter cuidado ao usar NVL. por exemplo, se de um lado temos um valor null e do outro temos por exemplo o valor 1, se colocarmos nvl(valor1,1) já teremos problemas na comparação
pois o oracle transformara o valor nulo em 1 e ira comparar com o outro valor que também é 1 dizendo que são valores iguais, "enganando" o programador.

declare

  v_valor1 varchar2(10):= null;
  v_valor2 varchar2(10):= '1';
  
  begin  
    
    if nvl(v_valor1,1) != nvl(v_valor2,1) then
      dbms_output.put_line('Valor '|| v_valor1||' é diferente a '||v_valor2);
    else
      dbms_output.put_line('Valor '|| v_valor1||' é igual a '||v_valor2);            
    end if; 
  
  end;  

  Valor  é igual a 1
  (Resultado errado)


  A melhor maneira de comparar valores nulos é utilizar:
        v_valor1 <> v_valor2 or (v_valor1 is null and v_valor2 is not null)or (v_valor1 is not null and v_valor2 is null)
  conforme abaixo:

  declare

  v_valor1 varchar2(10):= null;
  v_valor2 varchar2(10):= '1';
  
  begin 

    if v_valor1 <> v_valor2 or (v_valor1 is null and v_valor2 is not null)
        or (v_valor1 is not null and v_valor2 is null) then
      dbms_output.put_line('Caso 1 - Valor '|| v_valor1||' é diferente de '||v_valor2);
    else
      dbms_output.put_line('Caso 1 - Valor '|| v_valor1||' é igual a '||v_valor2);
    end if;

   end;

Nenhum comentário:

Postar um comentário