Dúvida SQL no Oracle: 'IF' no 'WHERE'?

Pessoal, eu estou com uma situação onde devo selecionar várias coisas de uma tabela, com uma série de restrições. Mas uma delas está me atrasando: eu tenho que verificar um atributo “ATRIB2” e, se ele for diferente de 0, fazer um join com uma tabela de controle de usuários por ele. Algo assim:

select * 
from 
   tabela1,
   tabela_controle controle1,
   tabela_controle controle2
where
   tabela1.atrib1 = controle1.atrib
   and tabela1.atrib2 = controle2.atrib // somente se for != 0!!!

Alguém pode me dar uma ajuda nessa? Já pesquisei pelas cláusulas IF, DECODE e CASE, mas nenhuma delas me pareceu ser utilizável neste caso… :frowning:

Adicione issono final do seu select…

Hm, talvez eu não tenha me expressado bem: Eu preciso que as que tem

tabela1.atrib2 == 0

retornem, mas sem filtrar pelo

and tabela1.atrib2 = controle2.atrib 

Em algoritmo, seria algo como…

select * 
from 
   tabela1,
   tabela_controle controle1,
   tabela_controle controle2
where
   tabela1.atrib1 = controle1.atrib
   if tabela1.atrib2 != 0
      and tabela1.atrib2 = controle2.atrib // filtra
   else
      // não filtra

Não sei se entendi, mas você está querendo que retorne um número variável de colunas dependendo de uma condição? Isso não é possível em um banco de dados relacional…

O que você pode é fazer o join das três tabelas e fazer o teste de “se for diferente de zero, processa colunas da tabela controle2” na sua própria aplicação.

... and (tabela1.atrib2 = 0 or tabela1.atrib2 = controle2.atrib)

Não exatamente: o número de colunas é sempre o mesmo.

select 
   tabela1.id,
   tabela1.atrib1,
   tabela1.atrib2 
from 
   tabela1,
   tabela_controle controle1,
   tabela_controle controle2
where
   tabela1.atrib1 = controle1.atrib
   if tabela1.atrib2 != 0
      and tabela1.atrib2 = controle2.atrib // filtra
   else
      // não filtra

O que eu quero é que, se atrib2!=0, seja feito um filtro por ele; caso atrib2==0, não seja feito o filtro por ele (somente por atrib1). Fazer o controle na aplicação está realmente fora de cogitação, já que são algumas centenas de milhares de colunas… :?

[quote=gomesrod]... and (tabela1.atrib2 = 0 or tabela1.atrib2 = controle2.atrib)[/quote]

Quase! O problema de fazer isso é que, se tabela1.atrib2==0, ocorrerá tabela1 X controle2… retornando um monte de resultados repetidos. Distinct não ajuda, já que tenho alguns campos CLOB… :frowning:

Bom, eu não testei o código, mas acredito que o caminho deve ser por aqui!

select * from tabela1, tabela_controle controle1, tabela_controle controle2 where tabela1.atrib1 = controle1.atrib case when tabela1.atrib2 <> 0 then tabela1.atrib2 = controle2.atrib else null -- Não faz nada end

Abraços!

Vc pode uar a função MINUS:
http://www.techonthenet.com/sql/minus.php

Quando o atributo for !=0 irá subtrair o registro da query principal.

Interessante!

Essa função é do SQL ANSI? Tem em todos os SGBDs?

[quote=MarceloS][quote=gomesrod]... and (tabela1.atrib2 = 0 or tabela1.atrib2 = controle2.atrib)[/quote]

Quase! O problema de fazer isso é que, se tabela1.atrib2==0, ocorrerá tabela1 X controle2… retornando um monte de resultados repetidos. Distinct não ajuda, já que tenho alguns campos CLOB… :([/quote]
Não entendi! :frowning:
O que acontece de errado?

Que tal isso aqui:

select 
   tabela1.id,
   tabela1.atrib1,
   tabela1.atrib2 
from 
   tabela1
where
   tabela1.id in 
     (select 
          tabela1.id
       from
          tabela1, 
          tabela_controle controle1,
          tabela_controle controle2
       where
          tabela1.atrib1 = controle1.atrib 
          and tabela1.atrib2 &lt;&gt; 0
          and tabela1.atrib2 = controle2.atrib)
      or
   tabela1.id in 
     (select 
          tabela1.id
       from
          tabela1, 
          tabela_controle controle1
       where
          tabela1.atrib1 = controle1.atrib 
          and tabela1.atrib2 = 0)

Pessoal, consegui resolver assim:

select * 
from 
   tabela1,
   tabela_controle controle1,
   tabela_controle controle2
where
   tabela1.atrib1 = controle1.atrib
   and (
             tabela1.atrib2 = 0
          or 
             tabela1.atrib2 = controle2.atrib
          )
    and controle1.user = 1 // usuário do sistema, faltou mencionar, my fault
    and controle2.user = controle1.user

Tinha esquecido de especificar o número do usuário no sistema, e por isso que não tinha conseguido fazer a dica do gomesrod funcionar… :oops:

Valeu pela ajuda de todos!! :stuck_out_tongue:

ola Pessoal to com uma duvida eu to executando um select pra fazer um sum na tabela de multas so que qando nao tem multa no periodo que to pedindo ele nao retorna nada ai nao aparece nada no quikreport ele era que aparecer zero quando for null so que nao consigo fazer sera que alguem pode me ajudar?

eu to usando oseguinte comando so que nao funciona

select
V.CODIGOEMPRESA AS EMPRESA,
SUM(M.VALORTOTALMULTA)AS TOTAL_M,
case
when SUM(M.VALORTOTALMULTA) <> 0 then SUM(M.VALORTOTALMULTA)
when SUM(M.VALORTOTALMULTA) = 0 then 0
when SUM(M.VALORTOTALMULTA) = null then 0
else 1 - 1 end
from
dvs_multa M,
FRT_CADVEICULOS V
WHERE
V.CODIGOVEIC = M.CODIGOVEIC
–AND V.CODIGOEMPRESA = 2
AND M.DATAVECTOMULTA BETWEEN ‘01-JUN-2009’ AND '30-JUN-2009’
GROUP BY
V.CODIGOEMPRESA

hmmm…
Assim não resolve?

 select V.CODIGOEMPRESA AS EMPRESA,
        SUM(nvl(M.VALORTOTALMULTA,0)) AS TOTAL_M

   FROM dvs_multa M, FRT_CADVEICULOS V

   WHERE V.CODIGOVEIC = M.CODIGOVEIC
    AND M.DATAVECTOMULTA BETWEEN '01-JUN-2009' AND '30-JUN-2009'

  GROUP BY V.CODIGOEMPRESA 

vo tentar deste jeito… ai ja respondo!!!

vlw…

fiz como vc havia me falado mas ficou do mesmo jeito qdo nao tem dado a ser puchado ele nao traz nada, so que na aplicaçao como esta dentro de outra consultas ai sai tudo embranco por causa disso… tipo ao invez de nao parecer registro teria q colocar o zero.

Provavelmente o que queres então é fazer um outer join com a tabela dvs_multa.

 select V.CODIGOEMPRESA AS EMPRESA,  
        SUM(nvl(M.VALORTOTALMULTA,0)) AS TOTAL_M  
   
   FROM FRT_CADVEICULOS V outer dvs_multa M  
   
   WHERE V.CODIGOVEIC = M.CODIGOVEIC  
    AND M.DATAVECTOMULTA BETWEEN '01-JUN-2009' AND '30-JUN-2009'  
   
 GROUP BY V.CODIGOEMPRESA  

Muito obrigo… deu certo!!!
Te devo uma… fico bem legal o que eu precisava…

vlw pela ajuda.