Como retornar a segunda menor data

Dúvidas, dicas e truques de SQL, Select, Update, Delete, cláusulas, operações com joins, Funções em SQLs, etc
  

Mensagemem Qui, 18 Out 2007 9:28 am

Tenho uma tabela com código e data, onde o codigo se repete para datas distintas.
Se eu fizer o min(data), codigo eu obtenho a menor data por codigo.
Mas eu preciso da segunda menor data.
A principio fiz um select retornando a menor data dentro de um select usando not in e em seguinda o select principal retornando a 2º menor data exemplo:

Código: Selecionar todos
select min(data),codigo
from tabela
where codigo in (select codigo
                 from tabela
                 where codigo not in (select a.codigo
                                      from tabela a
                                      where data in (select min(b.data)
                                                     from tabela b
                                                     where  b.codigo =  a.codigo)


Existe alguma maneira mais simples de retornar a 2º menor data?????

Grato
brauliomsf
Localização: SP

Braulio Moizes

Mensagemem Qui, 18 Out 2007 9:59 am

tenta ai

Código: Selecionar todos
select  min(a.data),a.codigo
  from  tabela a
where  a.data > (select min(b.data)
                            from tabela b
                          where b.codigo = a.codigo)
rodfbar
Localização: Batatais - SP

Mensagemem Qui, 18 Out 2007 6:50 pm

Pelo que entendi da sua consulta, você está retornando todos os códigos com a segunda menor data da tabela, certo?

Código: Selecionar todos
select codigo
     , data
from
(
  select t.codigo
       , t.data
       , dense_rank() over (order by t.data asc) posicao
  from   tabela t
)
where  posicao = 2
;


Não tenho como testar essa query no momento, mas acredito que funcione :D
rogenaro
Localização: Londrina - PR

Rafael O. Genaro

Mensagemem Seg, 05 Nov 2007 1:10 pm

kara... acho que o "ROWNUM" também DA PRA FAZER... TENTA aí!

Código: Selecionar todos
select codigo, data
  from (select t.codigo, t.data, rownum posicao
          from tabela t
         order by t.data asc)
where posicao = 2;


falou!!
Renan Orati
Localização: São José do Rio Preto - SP

Mensagemem Seg, 05 Nov 2007 6:57 pm

kara... acho que o "ROWNUM" também DA PRA FAZER... TENTA aí!

Código:

select codigo, data
from (select t.codigo, t.data, rownum posicao
from tabela t
order by t.data asc)
where posicao = 2;


falou!!


Só uma correção:
o rownum é gerado antes da execução da cláusula order by, portanto o registro retornado pode não ser a segunda menor data... Seria necessário adicionar mais um nível na consulta:
Código: Selecionar todos
select codigo, data
from 
(
  select rownum posicao, a.*
  from
  (
    select t.codigo, t.data
    from   tabela t
    order by t.data asc
  ) a
)
where posicao = 2;
rogenaro
Localização: Londrina - PR

Rafael O. Genaro

Mensagemem Qui, 06 Dez 2007 12:41 pm

pessoal, estou com uma dúvida em relação a datas num Select, e estou postando aqui pra não criar um novo tópico só pra isso:

esse será minha select interna:

Código: Selecionar todos
SELECT Max(g.lora_dt) Ultima_Ligacao
  FROM gelogramal g, rhfunc
WHERE g.func_cd = rhfunc.func_cd
   AND g.empr_cd = rhfunc.empr_cd
   AND g.inra_ddd = '43'
   AND g.inra_nr = '33210710'
   AND g.lora_dt NOT BETWEEN To_Date('01/12/2007','DD/MM/YYYY')
                      AND To_Date('30/12/2007','DD/MM/YYYY');


ela me retorna:

ULTIMA_LIGACAO
10/09/2007 12:00:00

Se eu coloco ela nesse SQL, me retorna 2 registros(!?)
Código: Selecionar todos
SELECT rhpessoa.pess_nm_nome,
       rhfunc.func_cd,
       gelogramal.lora_dt
  FROM rhpessoa, rhfunc, gelogramal
WHERE rhfunc.pess_cd = rhpessoa.pess_cd
   AND gelogramal.func_cd = rhfunc.func_cd
   AND gelogramal.empr_cd = rhfunc.empr_cd
   AND gelogramal.inra_ddd = '43'
   AND gelogramal.inra_nr = '33210710'
   AND gelogramal.lora_dt NOT BETWEEN To_Date('01/12/2007','DD/MM/YYYY')
                                  AND To_Date('30/12/2007','DD/MM/YYYY')

   AND gelogramal.lora_dt = (SELECT Max(g.lora_dt) Ultima_Ligacao
                          FROM gelogramal g
                         WHERE g.func_cd = rhfunc.func_cd
                           AND g.empr_cd = rhfunc.empr_cd
                           AND g.inra_ddd = gelogramal.inra_ddd
                           AND g.inra_nr = gelogramal.inra_nr
                           AND g.lora_dt NOT BETWEEN To_Date('01/12/2007','DD/MM/YYYY')
                                                       AND To_Date('30/12/2007','DD/MM/YYYY'))


      AND gelogramal.lora_bo_particular = 'S';



Código: Selecionar todos
FULANO 1   01/09/2007 10:04:00
FULANO 2   10/09/2007 12:00:00 --Deveria retornar somente esse registro! (maior data)


porque isso acontece?!, ora, se a Select interna retorna a maior data (SELECT Max(g.lora_dt) Ultima_Ligacao), porque a comparação não está funcioando nesse caso?!?!?!
Porva
Localização: São Paulo/SP

Rafael S. Nunes
São Paulo/SP

Mensagemem Qui, 06 Dez 2007 2:03 pm

E ai Porva,

cara pelo q eu entendi seu select principal lê uma tabela de funcionarios, e a subconsulta q existe no where dela está amarrada ao funcionario também.. dessa forma será exibido mais de um registro.... será q não é isso?

[]'s
Tineks
Localização: Araraquara - SP

Cristiano (Tineks)
Araraquara - SP

Mensagemem Qui, 06 Dez 2007 2:55 pm

Cristiano, retirei aqui a comparação de funcionário e empresa e funcinou, mas eu tenho poucos registros nesse caso, meu medo é: eu não preciso relacionar o Select interno com o externo??? o select interno não vai me trazer um max(data) de outro registro que não tenha nada a ver?, não saquei bem a lógica do mecanismo! :(
Porva
Localização: São Paulo/SP

Rafael S. Nunes
São Paulo/SP

Mensagemem Qui, 06 Dez 2007 3:06 pm

Então, eu não entendi o q você realmente precisa..
essa sua consulta deve buscar todos os funcionários e trazer a maior data de cada um ou somente a maior data entre todos??

[]'s
Tineks
Localização: Araraquara - SP

Cristiano (Tineks)
Araraquara - SP

Mensagemem Qui, 06 Dez 2007 3:28 pm

a maior data entre todos

deixa eu tentar ser mais claro e explicar a bagunça:


eu tenho o controle de ramais que funciona da seguinte forma, quando a ligação for particular do funcionário, a empresa cobra por ela, imagine que no período de 01/09/2007 a 30/09/2007 o funcionário FABIO e o funcionário RAFAEL ligaram para um telefone que não é um contato da empresa, um amigo deles por exemplo cujo número do telefone é: 43
33334444:

eles ligaram na seguinte data/seqüência:

Nome Data Nº tel
----------------------------------------
FABIO 01/09/2007 43 33334444
RAFAEL 10/09/2007 43 33334444


quando o usuário pedir um filtro das ligações do mês de Dezembro/2007, novamente eu verifico

se existem registros desse telefone externo (43 33334444) FORA do período informado e com funcionário já relacionado*, procurando ocorrências de funcionários que já estejam relacionados a esse número, aí no bloco tabular eu já traria esse funcionário com uma cor diferente sugerindo que aquele número pertence a ele, o que quero é trazer um funcionário apenas, no caso, o último que ligou pra esse número.

dae eu pensei em fazer um Select que retorne o a última ligação feita pro telefone (43 33334444) e que esteja com o funcioário já relacionado lá atrás, no mês de Setembro


*o chefe do depto relaciona o funcionário da seguinte forma, os registros são exibidos num bloco multirecord, e passa uma lista no papel mesmo, pelo depto pra cada funcinário identificar suas ligações, aí o usuário (no sistema) amarra essas ligações aos funcionários.
Porva
Localização: São Paulo/SP

Rafael S. Nunes
São Paulo/SP

Mensagemem Qui, 06 Dez 2007 3:43 pm

olha aí Cristiano, pra ficar mais visual a coisa

quando eu pedir o intervalo de dezembro (01 a 31), ele novamente terá esse telefone '33210710', dae eu trago automaticamente o último funcionário que ligou pra ele, no caso, eu mesmo no exemplo..

Imagem
Porva
Localização: São Paulo/SP

Rafael S. Nunes
São Paulo/SP

Mensagemem Qui, 06 Dez 2007 5:27 pm

E ai Porva, beleza??
cara, da uma olhada nesse codigo, vê se é +- isso..

Código: Selecionar todos
SQL> select * from mens_erro;

NOME                                     DATA      TEL
---------------------------------------- --------- ---------------
Fabio                                    01-SEP-07 43 33334444
Rafael                                   10-SEP-07 43 33334444

SQL> SELECT a.*, nvl2(b.maxdata,'Ultimo',null) flag
  2    FROM mens_erro a,
  3         (SELECT MAX (DATA) maxdata
  4            FROM mens_erro) b
  5   WHERE a.DATA BETWEEN TO_DATE ('01/09/2007', 'DD/MM/YYYY')
  6                    AND TO_DATE ('30/09/2007', 'DD/MM/YYYY')
  7     AND a.data = b.maxdata(+)
  8  /

NOME                                     DATA      TEL             FLAG
---------------------------------------- --------- --------------- ------
Rafael                                   10-SEP-07 43 33334444     Ultimo
Fabio                                    01-SEP-07 43 33334444


[]'s
Tineks
Localização: Araraquara - SP

Cristiano (Tineks)
Araraquara - SP

Mensagemem Sex, 07 Dez 2007 7:57 am

Cristiano, eu que tava com a cabeça quente ontem e não tava conseguindo pensar direito!, fiz do jeito simples mesmo, tipo, como eu tava relacionando funcionário da consulta interna com a externa, e tava trazendo mais de um registro por isso, simplesmente fiz as duas consultas praticamente idênticas, mas a interna com MAX e relacionando na próprio consulta com funcionário:

Código: Selecionar todos
SELECT rhpessoa.pess_nm_nome,
       rhfunc.func_cd,
       gelogramal.lora_dt
  FROM rhpessoa, rhfunc, gelogramal
WHERE rhfunc.pess_cd = rhpessoa.pess_cd
   AND gelogramal.func_cd = rhfunc.func_cd
   AND gelogramal.empr_cd = rhfunc.empr_cd
   AND gelogramal.lora_dt = (  SELECT Max(g.lora_dt)
                                 FROM gelogramal g, rhfunc f --relacionei internamente RHFUNC
                                WHERE g.func_cd  = f.func_cd
                                  AND g.empr_cd  = f.empr_cd
                                  AND g.inra_ddd = '43'
                                  AND g.inra_nr  = '33210710'
                                  AND g.lora_bo_particular = 'S'
                                  AND g.lora_dt NOT BETWEEN TO_DATE('01/12/2007','DD/MM/YYYY')
                                                        AND TO_DATE('30/12/2007','DD/MM/YYYY') );



agora uma curiosidade, como o Oracle procede nesse caso, ele executa a consulta interna primeiro????
Porva
Localização: São Paulo/SP

Rafael S. Nunes
São Paulo/SP

Mensagemem Sex, 07 Dez 2007 8:14 am

Então Porva, beleza cara?

Seguinte, creio que, não é que ele LÊ primeiro o interno mas, creio que ele inicialize o Parse, de baixo para cima.

Me corrijam se eu estiver errado.
Trevisolli
Localização: Araraquara - SP

Abraço,

Trevisolli
OCA Oracle PL/SQL Developer Certified Associate
OCP Oracle Forms Developer Certified Professional
Araraquara-SP

Mensagemem Sex, 07 Dez 2007 8:18 am

E ai Porva, beleza?

Cara, na subconsulta você colocou a tabela rhfunc, ela está se relacionando com a gelogramal, porem esse relacionamento eu acho desnecessário pois você não está fazendo nenhum filtro na rhfunc, e também não esta utilizando nenhum campo dela com a consulta externa....
Agora fique com uma duvida, sobre esse trecho aqui.
Código: Selecionar todos
... AND gelogramal.lora_dt = (  SELECT Max(g.lora_dt) ...

fazendo dessa forma você só vai trazer o ultimo usuário que fez a ligação!!!???... é isso mesmo? ou teria q ser um outer join nesse ponto.

[]'s
Tineks
Localização: Araraquara - SP

Cristiano (Tineks)
Araraquara - SP

Mensagemem Sex, 07 Dez 2007 8:29 am

puts, é verdade cara, viajei de novo!

e sim, eu só preciso trazer 1 funcionário mesmo, o último que ligou 'MAX(data)'

então, isso que está fo*a de sacar, porque se eu relacino a consulta interna com a externa, aí cai naquele caso de trazer mais de 1 funcionário, e isso não pode acontecer

esqueçam meu SQL aí do post acima, está errado :roll:
Porva
Localização: São Paulo/SP

Rafael S. Nunes
São Paulo/SP

Mensagemem Sex, 07 Dez 2007 8:53 am

eu até tentei um:

Código: Selecionar todos
SELECT rhpessoa.pess_nm_nome,
       rhfunc.func_cd,
       gelogramal.lora_dt
  FROM rhpessoa, rhfunc, gelogramal
WHERE rhfunc.pess_cd = rhpessoa.pess_cd
   AND gelogramal.func_cd = rhfunc.func_cd
   AND gelogramal.empr_cd = rhfunc.empr_cd
   AND gelogramal.inra_ddd = '43'
   AND gelogramal.inra_nr  = '33210710'
   AND gelogramal.lora_bo_particular = 'S'
   AND gelogramal.lora_dt NOT BETWEEN To_Date('01/12/2007','DD/MM/YYYY')
                                  AND To_Date('30/12/2007','DD/MM/YYYY')
   AND ROWNUM < 2
ORDER BY gelogramal.lora_dt DESC;


mas ele executa o ROWNUM antes do ORDER BY, aí fica na mesma!
Porva
Localização: São Paulo/SP

Rafael S. Nunes
São Paulo/SP

Mensagemem Sex, 07 Dez 2007 10:24 am

resolvi aqui Cristiano, só tirei o relacionamento da consulta interna com a externa, valeu pela paciência aí (y)
Porva
Localização: São Paulo/SP

Rafael S. Nunes
São Paulo/SP

Mensagemem Sex, 07 Dez 2007 10:32 am

Legal cara, desculpa a demora a responder, é q hj estou bem enrolado aqui. hehehehehe

[]'s!!!
Tineks
Localização: Araraquara - SP

Cristiano (Tineks)
Araraquara - SP

Mensagemem Sex, 07 Dez 2007 12:15 pm

o loco meo, que isso, hehe, tu foi prestativo pra caramba, valeu mais uma vez

perguntei prum cara bozão do SQL que trabalha aqui mas que estava de férias :)

eu pensei que deveria ter essa ligação entre os dois selects, mas não :S
Porva
Localização: São Paulo/SP

Rafael S. Nunes
São Paulo/SP


  • Veja também
    Respostas
    ExibiÇões
    Última mensagem

      Próximo

      Voltar para SQL

      Quem está online

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