Ajuda em uma consulta em oracle

Dúvidas, dicas e truques de SQL, Select, Update, Delete, cláusulas, operações com joins, Funções em SQLs, etc
vinicius.quadros
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 4
Registrado em: Ter, 20 Ago 2013 8:52 am

Bom dia a todos estou tendo dificuldade em uma consulta no resultado.

Tenho duas tabelas:

Tabela A

Selecionar tudo

P	Inicial	Final
112010	0	999
112010	1000	1999
112010	2000	2999
112010	3000	3999
112010	4000	4999
112010	5000	5999
112010	6000	6999
112010	7000	7999
112010	8000	8999
112010	9000	9999
112060	0	999
112060	1000	1999
112060	2000	2999
112060	3000	3999
112060	4000	4999
112060	5000	5999
112060	6000	6999
112060	7000	7999
112060	8000	8999
112060	9000	9999
Tabela B

Selecionar tudo

P	Inicial	Final
112010	0	4999
112010	7000	9999
112060	0	1999
112060	2000	8999
112060	9000	9999
Tenho que ter como resultado:

Selecionar tudo

P	Inicial	Final
112010	5000	5999
112010	6000	6999
Este meu resultado consiste no que tenho na tabela A e não tenho na tabela B, referente aos campos inicial e final. Exemplo no P = 112010 tenho na Faixa A inicial de 0 a 9999 e na B ele salta de 5000 a 6999 por isto me traz no resultado mas no P = 112060 ele tem de 0 a 9999 na A e na B por isto não tem que trazer no resultado.

Estou fazendo a consulta abaixo:

Selecionar tudo

select distinct a.p,
                a.inicial,
                a.final
        from A a
        inner join B b on a.p = b.p
        where a.p in (112010, 112060)
              and a.inicial > b.inicial
              and a.final > b.final
        order by a.p
Mas me traz o resultado:

Selecionar tudo

112010	5000	5999
112010	6000	6999
112010	7000	7999
112010	8000	8999
112010	9000	9999
112060	2000	2999
112060	3000	3999
112060	4000	4999
112060	5000	5999
112060	6000	6999
112060	7000	7999
112060	8000	8999
112060	9000	9999
Alguém poderia me ajudar a trazer este resultado?

Selecionar tudo

P	Inicial	Final
112010	5000	5999
112010	6000	6999
Obrigado.
DanielNN
Moderador
Moderador
Mensagens: 641
Registrado em: Seg, 03 Set 2007 3:26 pm
Localização: Fortaleza - CE
att,

Daniel N.N.

Cara, teria um jeito bem simples de resolver se na tabela B tivesse o mesmo tamanho de range que a tabela A(esta traz de mil a mil, já a B traz um range maior, como de 0 - 4999.)
Se a tabela B tivesse o mesmo nivel de range bastaria fazer um MINUS.

Selecionar tudo

Select P, INICIAL, FINAL FROM A
MINUS
Select P, INICIAL, FINAL FROM B;
Como, pelo visto, você não tem como alterar os inputs da tabela B, você tera que fazer um select em cima da tabela B que traga esta visão, aí possa usar o select indicado.

Aguardo retorno.
vinicius.quadros
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 4
Registrado em: Ter, 20 Ago 2013 8:52 am

Noctifero obrigado pelo retorno, mas não posso fazer esta alteração pois ate mesmo na tabela A pode se ter dados desta forma. Ta fo*a! já não sei o que fazer.
DanielNN
Moderador
Moderador
Mensagens: 641
Registrado em: Seg, 03 Set 2007 3:26 pm
Localização: Fortaleza - CE
att,

Daniel N.N.

Cara, gostei do probleminha.
Não tenho a apresentação do resultado como você gostaria mas acredito que seja a forma mais adequada de se trabalhar com eles.
Criei "2 tabelas" com os valores unitários, excluindo o range, uma com todos os valores da tabela A e outra com a B e pude realizar a diferença (MINUS).

Selecionar tudo

with tabela_a as 
(select 112010 p , 0 inicial ,999 final from dual
union all
select 112010 p , 1000 inicial ,1999 final from dual
union all
select 112010 p , 2000 inicial ,2999 final from dual
union all
select 112010 p , 3000 inicial ,3999 final from dual
union all
select 112010 p , 4000 inicial ,4999 final from dual
union all
select 112010 p , 5000 inicial ,5999 final from dual
union all
select 112010 p , 6000 inicial ,6999 final from dual
union all
select 112010 p , 7000 inicial ,7999 final from dual
union all
select 112010 p , 8000 inicial ,8999 final from dual
union all
select 112010 p , 9000 inicial ,9999 final from dual
-----
union all
select 112060 p , 0 inicial ,999 final from dual
union all
select 112060 p , 1000 inicial ,1999 final from dual
union all
select 112060 p , 2000 inicial ,2999 final from dual
union all
select 112060 p , 3000 inicial ,3999 final from dual
union all
select 112060 p , 4000 inicial ,4999 final from dual
union all
select 112060 p , 5000 inicial ,5999 final from dual
union all
select 112060 p , 6000 inicial ,6999 final from dual
union all
select 112060 p , 7000 inicial ,7999 final from dual
union all
select 112060 p , 8000 inicial ,8999 final from dual
union all
select 112060 p , 9000 inicial ,9999 final from dual
)
,tabela_b as
(
select 112010 p , 0 inicial ,4999 final from dual
union all
select 112010 p , 7000 inicial ,9999 final from dual
union all
select 112060 p , 0 inicial , 1999 final from dual
union all
select 112060 p , 2000 inicial ,8999 final from dual
union all
select 112060 p , 9000 inicial ,9999 final from dual
)

SELECT a.p
     , x.valor
  FROM (SELECT t.menor + LEVEL - 1 valor
          FROM (SELECT MIN(a.inicial) menor , MAX(a.final) maior FROM tabela_a a) t
        CONNECT BY LEVEL <= t.maior - t.menor + 1) x
     , tabela_a a
  where x.valor between a.inicial and a.final
   
MINUS

SELECT b.p
     , x.valor
  FROM (SELECT t.menor + LEVEL - 1 valor
          FROM (SELECT MIN(b.inicial) menor , MAX(b.final) maior FROM tabela_b b) t
        CONNECT BY LEVEL <= t.maior - t.menor + 1) x
     , tabela_b b
  where x.valor between b.inicial and b.final

order by 1 , 2
;
OBS:No seu caso pode desconsiderar toda clausula with (pois você tem as tabelas e dados e eu não).
vinicius.quadros
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 4
Registrado em: Ter, 20 Ago 2013 8:52 am

Nossa amigo interessante! Mas o complicado é fazer isto para os mais de 600 mil registros de cada uma das duas tabelas aff!
DanielNN
Moderador
Moderador
Mensagens: 641
Registrado em: Seg, 03 Set 2007 3:26 pm
Localização: Fortaleza - CE
att,

Daniel N.N.

Computador foi feito para processar, tenha pena disso não. :D
Avatar do usuário
fbifabio
Moderador
Moderador
Mensagens: 199
Registrado em: Ter, 22 Fev 2011 1:51 pm
Localização: São Paulo - SP
Contato:
Fábio Prado
www.fabioprado.net

@vinicius.quadros

Também gostei do problema e quebrei a cabeça aqui para resolvê-lo só com sql estático sem criar nenhuma função mas não consegui, então criei uma função e consegui resolver o problema. Veja abaixo a solução:

1- Em primeiro lugar, crie a função abaixo, que deverá retornar 0 quando os valores de entrada não forem encontrados na tabela b:

Selecionar tudo

create or replace function fc_verifica_valor (p_valor_p number, p_valor_inicial number, p_valor_final number) return number is
  type t_emp_dados is table of b%rowtype;
  v_tab_dados t_emp_dados;  
begin    
    select  * bulk collect into v_tab_dados
    from    b
    where   p = p_valor_p;
    
    for i in v_tab_dados.first .. v_tab_dados.last
    loop
      if (p_valor_inicial between  v_tab_dados(i).inicial and  v_tab_dados(i).final) then
          return 1;
      end if;
    end loop;    
    
    return 0;
end;
2- Agora chame a função criada no passo anterior comparando 0 com o retorno da função:

Selecionar tudo

select      distinct a.p, 
               a.inicial, a.final
from        a
where       a.p in (112010, 112060)
and         0 = hr.fc_verifica_valor(a.p, a.inicial, a.final)
PL/SQL é uma extensão de SQL. Sempre que não for possível resolver um problema com SQL, crie uma função!

[]s
DanielNN
Moderador
Moderador
Mensagens: 641
Registrado em: Seg, 03 Set 2007 3:26 pm
Localização: Fortaleza - CE
att,

Daniel N.N.

fbifabio,
gostei da sua solução, bem criativa.
Se o conjunto de dados das tabelas A e B SEMPRE seguirem este padrão, está PERFEITA.
Porém, por exemplo, se na tabela A tiver um range tipo "0 - 999" e na tabela B tiver qualquer número maior que 0 até 999 ( como "10 - 999"), acabará informando que o resultado apresentado é, ainda, "0 - 999" o que deveria ser apenas "0 - 9".
vinicius.quadros
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 4
Registrado em: Ter, 20 Ago 2013 8:52 am

Fabio,

você é demais rs!

Funcionou brilhantemente!

Obrigado.
Responder
  • Informação
  • Quem está online

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