[DICA] DECODE x CASE

Dúvidas, dicas e truques de PL/SQL. Aqui também vão assuntos relacionados a pacotes, triggers, funções, Java-Stored Procedures, etc
Responder
ricards
Rank: Programador Sênior
Rank: Programador Sênior
Mensagens: 52
Registrado em: Sáb, 29 Set 2007 12:59 am
Localização: Araraquara-SP
Contato:
Ricardo Neves
Analista e Instrutor Oracle Developer
Java Developer (JPA/JSF/Hibernate/WebServices/EJB)

DECODE x CASE


1 – Funcionalidade: O Oracle possui duas formas de trabalhar com condição dentro de consultas em Oracle SQL, o Case e o Decode. As duas formas tem a mesma função, que é permitir de forma dinâmica e prática obter um retorno de uma coluna com base em uma condição, ou seja, ter a possibilidade de usar condições semelhantes ao IF-THEN-ELSE em consultas.

Sendo assim, é possível definir de forma dinâmica e bem prática o que será exibido na tela, evitando, consultas com retorno de colunas em branco..

2 – Diferença: O exemplo abaixo mostra o tipo de trabalho com o Case e o Decode.

• O Decode irá traduzir os valores passados por uma coluna com o esquema de codificação (1, 2, 3, 4) e irá retornar os valores decodificados (“Azul”, “Branco”, “Amarelo”, “Verde”) referentes aos códigos.

• O Case é parecido com o Decode, eles tem uma forma de processo que vem lendo os valores da esquerda para a direita, avaliando um a um e quando encontra um valor verdadeiro, ele retorna o valor correspondente.

Por exemplo, você precisa saber qual a cor referente ao código 3, então, ele irá pesquisar esse valor e quando achar, retornará o valor equivalente, ou seja, “Amarelo”.
Qualquer expressão feita com o Case poderá ser feita com o Decode, mas é difícil ter a mesma flexibilidade e possivelmente, será desgastante escrever grandes códigos com o Decode. A diferença entre os dois é praticamente essa, que na verdade, faz com que o Case seja melhor de se trabalhar.
Exemplos:

Decode

Selecionar tudo

SELECT
  DECODE
  (
    V_NM_COR,
    1, 'Azul',
    2, 'Branco',
    3, 'Amarelo',
       'Verde'
  )
FROM dual;


Case Simples

Selecionar tudo

SELECT
CASE
    V_NM_COR
    WHEN 1  
      THEN 'Azul'
    WHEN 2  
      THEN 'Branco'
    WHEN 3
      THEN 'Amarelo'
    ELSE   'Verde'
  END
FROM dual;	
Case com Pesquisa

Selecionar tudo

SELECT
  CASE
    WHEN V_NM_COR = 1
      THEN 'Azul'
    WHEN V_NM_COR = 2
      THEN 'Branco'
    WHEN V_NM_COR = 3
      THEN 'Amarelo'
    ELSE 'Verde'
  END
FROM dual;
RodrigoValentim
Moderador
Moderador
Mensagens: 367
Registrado em: Ter, 25 Mar 2008 3:41 pm
Localização: Salvador - BA
Rodrigo Valentim
Analista de Sistemas
Oracle Developer

Campanha: Faça uma pesquisa antes de perguntar!!!

Seria interessante você colocar a fonte...

Copiar contudo da internet, mudar algumas letras é realmente complicado e vergonhoso.
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered

Eu não acho que foi COPIADO de um link... Tente pegar trechos do POST acima e procurar no GOOGLE.

Lembre-se que o segredo dos BONS BLOGS é ter conteúdo único e de qualidade! Ou seja, nem sempre o conteudo VEM de algum lugar como nas "monografias" ou "teses de mestrado"...

Ricards está de parabéns!
jh.padilha
Rank: Estagiário Júnior
Rank: Estagiário Júnior
Mensagens: 1
Registrado em: Qua, 28 Jan 2009 9:14 am
Localização: Porto Alegre - RS

Será que o doutor chegou a fazer realmente uma pesquisa ?

Quem sabe você acessa este link
http://www.via6.com/topico.php?tid=261353.

E ai nos diga algo sobre.

:?
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered

Tem razão !!!!

Então:

PARABÉNS AO VERDADEIRO AUTOR DO POST:

Autor: Rodrigo Valentim
Fonte: Artigo escrito para revista virtual DevMedia

(estranho que quando eu procurei no GOOGLE a primeira vez não retornou nada a respeito)...
Poxa Rodrigo, devia ter dito que o POST era seu !!! hehehe Desculpe aí bróder! Parabens por seu artigo!


Aqui vai mais um LINK a respeito do CASE x DECODE:
http://glufke.net/oracle/viewtopic.php?t=12

:-o
RodrigoValentim
Moderador
Moderador
Mensagens: 367
Registrado em: Ter, 25 Mar 2008 3:41 pm
Localização: Salvador - BA
Rodrigo Valentim
Analista de Sistemas
Oracle Developer

Campanha: Faça uma pesquisa antes de perguntar!!!

Dr Gori, uma simples pesquisa por Decode x Case no google e te mostrará na primeira página... mas sem problemas...

Na verdade, esse artigo foi escrito pra DevMidia a uns 3 anos aproximadamente e quando a gente se depara com algo que você faz com algumas virgulas fora do lugar, fica realmente dificil ler e não falar nada... :)

Abraço,
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered

Claro, fez bem em avisar! E obrigao pelo conteúdo !
paulaholti
Rank: Programador Pleno
Rank: Programador Pleno
Mensagens: 43
Registrado em: Sex, 29 Jan 2010 4:02 pm
Localização: sp
iniciante oracle pl/sql forms reports

Não queria abrir outro tópico, então vou levantar este para tirar uma duvida a respeito do decode .

Queria fazer algo mais menos assim :

Selecionar tudo

Select decode(sysdate-previsaoentrega, <=31,' Ainda no Prazo,>31,' Em Atraso' ) 
from locacao where previsaoentrega is not null
, mas não dá certo .

Tentei para teste isso :

Selecionar tudo

Select decode (10-5, <=5 . ' teste a1, >5, 'teste b', 'teste c') from dual;

Selecionar tudo

erro :ERRO na linha 1:
ORA-00936: expressão ausente
Me parece que o decode, não aceita comparacao com operadores, tem que ser valores "exatos" .. Como resolve isto ? ... (na apostila, so tem exemplos com valores sem operadores)

O b r i g a d a ! ! ! ! ! ! !
SergioLBJr
Rank: Oracle Guru
Rank: Oracle Guru
Mensagens: 448
Registrado em: Ter, 16 Jun 2009 3:07 pm
Localização: Parobé - RS
Sérgio Luiz Bonemberger Junior
Programador Junior
Parobé RS

[]s

é o decode não aceita compara se é menor ou se é maior.

pra fazer isso tu vai ter que improvisar alguma lógica.

Selecionar tudo

SELECT DECODE (&numero, NVL((SELECT &numero FROM dual WHERE &numero <5),6),'É menor que cinco', 'É maior ou igual a cinco') FROM dual 
diegolenhardt
Moderador
Moderador
Mensagens: 1177
Registrado em: Qui, 15 Out 2009 10:28 am
Localização: Recife

para testar maior e menor, tem um tal de greatest,

acho que é pra isso :D
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Você teria que usar greatest, least ou sign na comparação. Penso que o sign é mais intuitivo.
Ainda assim há diversas formas de fazer, mesmo com case. Só veja sua regra qual é, pois a comparação com 31 provavelmente quer indicar um período de um mês, não? Se for isso veja se o ADD_MONTHS não é o que você quer. Pois por exemplo o mês de fevereiro não possui 31 dias então o cálculo ficaria errado para alguns casos de teste.

Segue abaixo vários exemplos:

Selecionar tudo

SQL> with locacao as (
  2  select sysdate-15 as previsaoentrega from dual union all
  3  select sysdate-31 as previsaoentrega from dual union all
  4  select sysdate-40 from dual)
  5  -- fim dos dados de exemplo
  6  SELECT previsaoentrega,
  7         CASE
  8           WHEN SYSDATE - previsaoentrega <= 31 THEN
  9            'Ainda no Prazo'
 10           ELSE
 11            'Em Atraso'
 12         END status_case,
 13         decode(sign(SYSDATE - previsaoentrega - 31),
 14                1, 'Em Atraso', 'Ainda no Prazo') status_decode,
 15         CASE
 16           WHEN add_months(previsaoentrega, 1) >= SYSDATE THEN
 17            'Ainda no Prazo'
 18           ELSE
 19            'Em Atraso'
 20         END status_case_addmonths,
 21         decode(sign(SYSDATE - add_months(previsaoentrega, +1)),
 22                1, 'Em Atraso', 'Ainda no Prazo') status_decode_addmonths
 23    FROM locacao l;
 
PREVISAOENTREGA STATUS_CASE    STATUS_DECODE  STATUS_CASE_ADDMONTHS STATUS_DECODE_ADDMONTHS
--------------- -------------- -------------- --------------------- -----------------------
3/2/2010 09:52: Ainda no Prazo Ainda no Prazo Ainda no Prazo        Ainda no Prazo
18/1/2010 09:52 Ainda no Prazo Ainda no Prazo Ainda no Prazo        Ainda no Prazo
9/1/2010 09:52: Em Atraso      Em Atraso      Em Atraso             Em Atraso
 
SQL> 
paulaholti
Rank: Programador Pleno
Rank: Programador Pleno
Mensagens: 43
Registrado em: Sex, 29 Jan 2010 4:02 pm
Localização: sp
iniciante oracle pl/sql forms reports

Ainda não entendi direito,
Primeiro, como é esse select ai ? .. É um select só de 23 linhas. porque começa com WITH ?

Depois realizei teste separado com o decode (baseado no seu exemplo), mas não retornaram do jeito que era para ser,
talvez eu não tenha entendido a logica do select .

Selecionar tudo

--teste1------------------------------------------------------------------------

select sysdate, previsaoentrega ,decode(sign(SYSDATE - previsaoentrega - 31),1, 'Em Atraso', 'Ainda no Prazo') status_decode from locacao  

SQL> /

SYSDATE  PREVISAO STATUS_DECODE
-------- -------- --------------
19/02/10 30/01/10 Ainda no Prazo
19/02/10 20/03/12 Ainda no Prazo

--teste2-----------------------------------------------------------------------------

select sysdate, previsaoentrega,  decode(sign(SYSDATE - add_months(previsaoentrega, +1)),
1, 'Em Atraso', 'Ainda no Prazo') status_decode_addmonths
FROM locacao

SQL> /

SYSDATE  PREVISAO STATUS_DECODE_
-------- -------- --------------
19/02/10 30/01/10 Ainda no Prazo
19/02/10 20/03/12 Ainda no Prazo
Ainda to tentando isoladamente para ver se entendo.

O b r i g a d a ! ! ! ( a todos )
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

É mais provável que eu não tenha entendido a sua regra... você poderia explicá-la de um jeito simples de dando um exemplo de qual o esperado para uns casos por favor?
sp66d_rac6r
Rank: Estagiário Sênior
Rank: Estagiário Sênior
Mensagens: 9
Registrado em: Ter, 02 Dez 2008 10:43 am
Localização: Sorocaba-SP

E em termos de performance, Existe diferença entre usar o DECODE ou o CASE?

Forte abraço!
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Os dois causam consumo de CPU para avaliar as condições.

O melhor jeito para conseguir uma resposta boa é testando e, segundo os testes que fiz, não há muita distinção. Um bom motivo pode ser que essas funções nativas são implementadas em C dentro do próprio banco de dados de forma muito otimizada.

Selecionar tudo

Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 
Connected as fsitja
 
SQL> 
SQL> set timing on
SQL> declare
  2    v_temp number;
  3  begin
  4    for i in 1 .. 1000000
  5    loop
  6      select round(dbms_random.value) into v_temp from dual;
  7    end loop;
  8  end;
  9  /
 
PL/SQL procedure successfully completed
 
Executed in 38,954 seconds
SQL> declare
  2    v_temp number;
  3  begin
  4    for i in 1 .. 1000000
  5    loop
  6      select case when round(dbms_random.value) = 1
  7                  then 10 else -10 end
  8        into v_temp
  9        from dual;
 10    end loop;
 11  end;
 12  /
 
PL/SQL procedure successfully completed
 
Executed in 39,25 seconds
SQL> declare
  2    v_temp number;
  3  begin
  4    for i in 1 .. 1000000
  5    loop
  6      select decode(round(dbms_random.value), 1, 10, -10)
  7        into v_temp
  8        from dual;
  9    end loop;
 10  end;
 11  /
 
PL/SQL procedure successfully completed
 
Executed in 39,141 seconds
diegolenhardt
Moderador
Moderador
Mensagens: 1177
Registrado em: Qui, 15 Out 2009 10:28 am
Localização: Recife

fsitja,

muita coisa agora no oracle é java né?

principalmente o 10g em diante,

mas realmente o que for em mais baixo nivel será mais performatico mesmo, decode, nvl, etc
RodrigoValentim
Moderador
Moderador
Mensagens: 367
Registrado em: Ter, 25 Mar 2008 3:41 pm
Localização: Salvador - BA
Rodrigo Valentim
Analista de Sistemas
Oracle Developer

Campanha: Faça uma pesquisa antes de perguntar!!!

fsitja, realmente, porém, quando você comeca a por vários decodes, a cois acomplica um pouco para o entendimento como um todo..
SergioLBJr
Rank: Oracle Guru
Rank: Oracle Guru
Mensagens: 448
Registrado em: Ter, 16 Jun 2009 3:07 pm
Localização: Parobé - RS
Sérgio Luiz Bonemberger Junior
Programador Junior
Parobé RS

[]s

Concordo que é melhor usar o case quando o código ficaria muito "sujo" com o decode.

Mas o uso do mesmo vai depender da versão que estas trabalhando.

Me lembro que o case no forms que eu trabalhava não compilava, dae tinha passar para o banco.
Responder
  • Informação
  • Quem está online

    Usuários navegando neste fórum: Nenhum usuário registrado e 19 visitantes