Jump to content

Archived

This topic is now archived and is closed to further replies.

Pride_fns

[Resolvido] Usando CASE dentro do WHERE

Recommended Posts

Bom dia pessoal do IMasters!!!

 

Estou tentando fazer um CASE dentro da Cláusula WHERE e acontece o seguinte erro, "ORA-00920:operador relacional inválido" apontando para a segunda Condição do WHERE => "and cod_ben = 1821001".

 

Não conseguir descobrir o porquê do erro. E também gostaria de saber se este é um método apropriao para se usar o CASE dentro do WHERE!!

 

SELECT (....)
FROM (....)
WHERE CASE WHEN TO_CHAR(SYSDATE,'DD/MM/') < TO_CHAR(b.dtcad,'DD/MM/')
          THEN
              'and a.dt_vencto >= TO_DATE(TO_CHAR(b.dtcad, DD/MM/) || (TO_CHAR(SYSDATE, YYYY)-1))'
          ELSE
              'and a.dt_vencto >= TO_DATE(TO_CHAR(b.dtcad, DD/MM/) || (TO_CHAR(SYSDATE, YYYY)))'
     END
     and cod_ben = 1821001
     and ROWNUM = 1;

 

Quem puder ajudar com uma palhinha de sua experiência, fique a vontade!!!

 

Vlw galera do IMasters pelo ótimo Fórum!!!

Share this post


Link to post
Share on other sites

Não o CASE deve ser tratado como uma coluna

 

...
WHERE (CASE WHEN DATA < TRUNC(SYSDATE) THEN 'ANTIGA'
            WHEN DATA = TRUNC9SYSDATE) THEN 'HOJE'
            ELSE 'FUTURA' END) = 'HOJE'
...

Share this post


Link to post
Share on other sites

Obrigado mais uma vez Motta. Que pena, entendi mas...

 

O que seria mais aconselhável para se usar nesses caso que quero fazer um teste para saber qual condição vou usar no WHERE?

 

Seria algo como isso?

 

OBS.: Eu uso este mesmo CASE no SELECT só que dentro do THEN e do ELSE faço SUBSELECT's....

 

(....)
WHERE cod_ben = 1821001
     and ((a.dt_vencto >= TO_DATE(TO_CHAR(b.dtcad,'DD/MM/') || (TO_CHAR(SYSDATE,'YYYY')-1))) OR (a.dt_vencto >= TO_DATE(TO_CHAR(b.dtcad,'DD/MM/') || (TO_CHAR(SYSDATE,'YYYY')))))
     and a.dt_pagamento > a.dt_vencto
     and ROWNUM = 1;

 

Se for necessário posto o SQL todo!!! Muito Obrigado

Share this post


Link to post
Share on other sites

Tudo bem, realmente não soube transmitir, por isso vo colocar todo o SQL e explicar mais detalhadamente.

 

Como podem ver no SELECT faço um CASE para fazer SUBSELECT's separando o calculo de "Data Início do Ano Passado" e outro de "Data Início do Ano Atual".

 

Então no WHERE também tenho que fazer o mesmo CASE que criei no SELECT porque para cada caso uso uma condição diferente.

 

Como você explicou que não é possível utilizar o CASE deste modo, ainda não conseguir encontrar um outro método.

 

E 1000 desculpas se ficou muito grande!!!

 

SELECT cod_ben,
      CASE WHEN TO_CHAR(SYSDATE,'DD/MM/') < TO_CHAR(b.dtcad,'DD/MM/')
          THEN
              CASE WHEN TO_CHAR(a.dt_vencto - TO_DATE(TO_CHAR(b.dtcad,'DD/MM/') || (TO_CHAR(SYSDATE,'YYYY')-1))) > 0
                   THEN
                   ( 
                   SELECT SUM(a.dt_pagamento - a.dt_vencto)
                   FROM sis.boleto_ben a INNER JOIN sis.benefics b USING(cod_ben)
                                         INNER JOIN sis.ativacao_ben c USING(cod_ben)
                   WHERE c.dthr_final is null
                         and b.cod_emp = 0
                         and cod_ben = 1821001
                         and a.dt_vencto >= TO_DATE(TO_CHAR(b.dtcad,'DD/MM/') || (TO_CHAR(SYSDATE,'YYYY')-1))
                         and a.dt_pagamento > a.dt_vencto
                         and a.vlr_pago > a.vlr_boleto
                   )
                END
          ELSE
              CASE WHEN TO_CHAR(a.dt_vencto - TO_DATE(TO_CHAR(b.dtcad,'DD/MM/') || (TO_CHAR(SYSDATE,'YYYY')))) > 0
                   THEN
                   ( 
                   SELECT SUM(a.dt_pagamento - a.dt_vencto)
                   FROM sis.boleto_ben a INNER JOIN sis.benefics b USING(cod_ben)
                                         INNER JOIN sis.ativacao_ben c USING(cod_ben)
                   WHERE c.dthr_final is null
                         and b.cod_emp = 0
                         and cod_ben = 1821001
                         and a.dt_vencto >= TO_DATE(TO_CHAR(b.dtcad,'DD/MM/') || (TO_CHAR(SYSDATE,'YYYY')))
                         and a.dt_pagamento > a.dt_vencto
                         and a.vlr_pago > a.vlr_boleto
                   )
                END
     END qntd_acum
FROM sis.boleto_ben a INNER JOIN sis.benefics b USING(cod_ben)
                     INNER JOIN sis.ativacao_ben c USING(cod_ben)
WHERE CASE WHEN TO_CHAR(SYSDATE,'DD/MM/') < TO_CHAR(b.dtcad,'DD/MM/')
          THEN
              'and a.dt_vencto >= TO_DATE(TO_CHAR(b.dtcad, DD/MM/) || (TO_CHAR(SYSDATE, YYYY)-1))'
          ELSE
              'and a.dt_vencto >= TO_DATE(TO_CHAR(b.dtcad, DD/MM/) || (TO_CHAR(SYSDATE, YYYY)))'
     END
     and cod_ben = 1821001
     and ROWNUM = 1

Share this post


Link to post
Share on other sites

Este SQL está montando outro SQL ?

 

Pq alguns comandos estão entre aspas ?

Share this post


Link to post
Share on other sites

Este SQL está montando outro SQL ?

 

Pq alguns comandos estão entre aspas ?

 

1) É um SQL único!

 

2) Coloquei entre aspas apenas os itens dentro da função TO_CHAR pq foi assim que vi em exemplos na net!

>>> TO_CHAR(b.dtcad,'DD/MM/') = nesse caso so pego o dia/mês da data pra futuramente concatenar com um dos anos a depender do CASE que entrar no SELECT.

 

E também no THEN e ELSE do CASE do WHERE mas esse não vai contar pq está errado ne!! ^^

 

Mais uma vez, sei pouco em SQL, e o que aprendir inicialmente foi Postgre.Agora estou começando a usar o ORACLE!!!

 

Então não estou familiarizado como as funções são escritas!

Share this post


Link to post
Share on other sites

A ideia básica do CASE é transformar um ou mais campos da tabela.

 

Linhas em colunas

 

SELECT

(CASE WHEN FORMA_PGTO = 'CARTAO' THEN VALOR ELSE 0 END) CARTAO,

(CASE WHEN FORMA_PGTO = 'DINHEIRO' THEN VALOR ELSE 0 END) DINHEIRO,

(CASE WHEN FORMA_PGTO NOT IN ('CARTAO','DINHEIRO') THEN VALOR ELSE 0 END) OUTROS

FROM TABELA

 

Mudar colunas

 

SELECT

(CASE WHEN DATA < TRUNC(SYSDATE) THEN 'ANTIGA'

WHEN DATA = TRUNC9SYSDATE) THEN 'HOJE'

ELSE 'FUTURA' END) = 'HOJE') TIPO_DATA

FROM TABELA

 

Entre outros tratamentos

 

Dá uma lida nisto.

Share this post


Link to post
Share on other sites

A ideia básica do CASE é transformar um ou mais campos da tabela.

 

Linhas em colunas

 

SELECT

(CASE WHEN FORMA_PGTO = 'CARTAO' THEN VALOR ELSE 0 END) CARTAO,

(CASE WHEN FORMA_PGTO = 'DINHEIRO' THEN VALOR ELSE 0 END) DINHEIRO,

(CASE WHEN FORMA_PGTO NOT IN ('CARTAO','DINHEIRO') THEN VALOR ELSE 0 END) OUTROS

FROM TABELA

 

Mudar colunas

 

SELECT

(CASE WHEN DATA < TRUNC(SYSDATE) THEN 'ANTIGA'

WHEN DATA = TRUNC9SYSDATE) THEN 'HOJE'

ELSE 'FUTURA' END) = 'HOJE') TIPO_DATA

FROM TABELA

 

Entre outros tratamentos

 

Dá uma lida nisto.

 

Certo, eu já tinha entendido isso do CASE, pelo menos creio que estou fazendo certo no CASE do SELECT neh!!!?

pq faço tipo assim:

 

Vamos criar uma Data só com dia/mês =>> dtcad := 22/08;

e um Valor qualquer =>> A := 5;

 

SELECT (...)
CASE
WHEN TO_CHAR(SYSDATE,'DD/MM/') < TO_CHAR(dtcad) THEN
   CASE
   WHEN A > 2 THEN
      (SELECT pra pegar um SUM qualquer menos 1) [EX.: (5+3)-1 = 7]
   END
ELSE
   CASE
   WHEN A > 0 THEN
      (SELECT pra pegar um SUM qualquer) [EX.: (5+3) = 8]
   END
END VALIDACAO 
(....)

 

Agora no WHERE ele terá que fazer esse teste, SE lá no CASE do SELECT ele entrar na condição 'A > 2' irá entrar em uma condição X do WHERE [5+3)-1 = 7], SENÃO irá entrar em uma condição Y do WHERE [(5+3) = 8]. Este teste no WHERE que não sei como terei que fazer, porquê ele não tem como fazer as duas condições pois vai dar erro pq nao tem como ele ser 'A > 2' e 'A < 2' ao mesmo tempo.

 

OBS.: perceba que no meu Post anterior, onde coloquei todo o meu SQL, que utilizo da concatenação do (ano_atual -1) em um CASE e no outro só concateno o (ano_atual), nisso é que irei descobrir qual será a data inicial de onde irei fazer os calculos.

Share this post


Link to post
Share on other sites

O Case poderia ser unido.

 

SELECT (...)
CASE
WHEN (TO_CHAR(SYSDATE,'DD/MM/yyyy') < TO_CHAR(dtcad) and  A > 2 THEN
    (SELECT pra pegar um SUM qualquer menos 1) 
WHEN (TO_CHAR(SYSDATE,'DD/MM/yyyy') >= TO_CHAR(dtcad) and A > 0 THEN 
    (SELECT pra pegar um SUM qualquer)
ELSE
    (...)
END VALIDACAO 

Só não entendi o motivo deste select dentro do CASE.

Share this post


Link to post
Share on other sites

Bem, não expliquei porque prolongaria o post, mas se for o caso explicarei o SQL:

 

É feito o Cadastro de uma pessoa no Plano de Saúde dia '01/01/2001' será gerado o boleto sempre com Vencimento dias 10 de cada mês(PS.: nem sempre é dia 10).

 

Então serão os dias:

10/01/2001

10/02/2001

10/03/2001

(.....)

 

Vou ter que somar em cada mês os dias atrasados, por exemplo:

JAN

dt_boletoJAN = 10/01/2010

dt_pgtoJAN = 12/01/2010

dt_pgtoJAN - dt_boletoJAN = 2 (dias de atraso)

dias_atraso_total = 2 [dias de atraso total]

 

FEV

dt_boletoFEV = 10/02/2010

dt_pgtoFEV = 15/02/2010

dt_pgtoFEV - dt_boletoFEV = 5 (dias de atraso)

dias_atraso_JAN + dias_atraso_FEV =

2 + 5 = 7

 

E quando essa soma ultrapassar 60 dias de atraso até o aniversário do cliente, ou seja, no dia 01/01/2002 a empresa poderá cancelar o contrato. Mas todo dia de aniversário, ou seja, 01/01/2002 ... 01/01/2003 ... 01/01/2004 ... e assim por diante, começará a ser contado os dias de atraso novamente do 0(ZERO).

 

Por exemplo: se no dia 31/12/2003 ele tiver a soma de dias atrasados igual a 59 no dia 01/01/2004 terá 0 dias de atraso porque começará a contar novamente só que para o novo período que será de dia 01/01/2004 à 31/12/2004.

 

Por isso pego o dia/mes da data de cadastro e testo se é maior que a data atual, para descobrir em qual período vou começar a contar. POr exemplo:

A data de cadastro foi dia '22/08/2001';

A data atual é '13/06/2010';

*separo o dia/mÊs das datas;

 

SE 22/08 > 13/06 já sei que a data inicial pra fazer as somas será 22/08/2009;

SENÂO a data inicial pra fazer as somas será 22/08/2010.

Por isso quebro o Ano da data, para depois Concatenar com o Ano que quero.

 

Isso que o SELECT do CASE faz:

SE entrar no THEN faz o cálculo de soma onde data_boleto >= '22/08/2009';

SENÂO faz o cálculo de soma onde data data_boleto >= '22/08/2010';

 

Logo no WHERE ele terá que fazer um tipo de teste mais ou menos assim:

WHERE CASE WHEN 22/08 > 13/06
          THEN
              'data_boleto >= 22/08/2009'
          ELSE
              'data_boleto >= 22/08/2010'
     END

 

Obrigado por estar tentando me ajudar!!!

Share this post


Link to post
Share on other sites

Supondo que CLIENTE.VIGENCIA seja a vigência atual do cidadão ...

 

Pois os boletos anteriores a vigência não consta mais.

 

Seria +ou- isto.

 

SELECT CLIENTE.NOME,
       BOLETO.REFERENCIA,
       (CASE WHEN (NVL(BOLETO_DT_PGTO,TRUNC(SYSDATE)) > BOLETO.DT_VENCIMENTO)) 
               THEN  (NVL(BOLETO_DT_PGTO,TRUNC(SYSDATE)) - BOLETO.DT_VENCIMENTO)
             ELSE 0 END) DIAS_ATRASO
FROM   CLIENTE,BOLETOS
WHERE  BOLETO.REFERENCIA <= ADD_MONTHS(CLIENTE.VIGENCIA,12)	


SELECT CLIENTE.NOME,
       SUM( 
       (CASE WHEN (NVL(BOLETO_DT_PGTO,TRUNC(SYSDATE)) > BOLETO.DT_VENCIMENTO)) 
               THEN  (NVL(BOLETO_DT_PGTO,TRUNC(SYSDATE)) - BOLETO.DT_VENCIMENTO)
             ELSE 0 END)
          ) DIAS_ATRASO
FROM   CLIENTE,BOLETOS
WHERE  BOLETO.REFERENCIA <= ADD_MONTHS(CLIENTE.VIGENCIA,12)
GROUP BY CLIENTE.NOME

PS Trabalho com Plano de Saúde também.

Share this post


Link to post
Share on other sites

hehehe .... que coincidencia!!! ^^

 

Motta desculpa a minha ignorância, mas como já disse sou inexperiente na área. Mas...

 

1º)

O que você consegue pegar aki? eu sei que o NVL troca um valor NULL pelo que a gnt kiser, mas não entendi pra que serve desse jeito que tu colocou!!!?????

NVL(BOLETO_DT_PGTO,TRUNC(SYSDATE))

 

2º)

Também não conseguir entender o que seria o CLIENTE.VIGENCIA (data_hoje?)

 

3º)

E o BOLETO.REFERENCIA (data_vencimento do boleto?)

 

4º)

Se faz com dois SELECTS mesmo? Porquê você só faz o SUM no segundo SELECT se são praticamente iênticos, com excessão de um item no select e o group by?

 

Sinceramente trabalhar com Data é muuuito trabalhoso!!! hehehe

 

Muito Obrigado

Share this post


Link to post
Share on other sites

1º)

O que você consegue pegar aki? eu sei que o NVL troca um valor NULL pelo que a gnt kiser, mas não entendi pra que serve desse jeito que tu colocou!!!?????

NVL(BOLETO_DT_PGTO,TRUNC(SYSDATE))

 

Se estiver em aberto (data nula) conta os dias até o data corrente da execução

 

2º)

Também não conseguir entender o que seria o CLIENTE.VIGENCIA (data_hoje?)

 

Não, seria a data da vigência do contrato do usuário, se renovou em 01/02/2010 passa a ser esta data.

 

3º)

E o BOLETO.REFERENCIA (data_vencimento do boleto?)

Não, a referência (ano e mês) relativos ao mês cobrança do boleto.

 

4º)

Se faz com dois SELECTS mesmo? O que você pega em cada um?

 

Não, foram apenas dois exemplos.

Share this post


Link to post
Share on other sites

×

Important Information

Ao usar o fórum, você concorda com nossos Terms of Use.