Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Condição de junção do Oracle com o Top 1


Ainda não entendi qual disco, no seu exemplo, você queria, então deixe-me dar algumas alternativas.

Eu deduzi de sua declaração de problema que você deseja a data efetiva mais recente das disponíveis. Como há laços envolvidos, você não pode usar max() (como você já declarou) e row_number() é o caminho a seguir:
with cte as (
  select
    addrid, effectdt, xpirdt,
    row_number() over (partition by addrid order by effectdt desc) as rn
  from addrdata
)
select
  addrid, effectdt, xpirdt
from cte
where rn = 1

A próxima parte foi onde você me perdeu com os nulos... Se sua classificação secundária for por data de expiração e você quiser que um valor nulo supere a última data de expiração, então você faria o pedido pela data de expiração e colocaria nulls first :
with cte as (
  select
    addrid, effectdt, xpirdt,
    row_number() over 
        (partition by addrid order by effectdt desc, xpirdt nulls first) as rn
  from addrdata
)
select
  addrid, effectdt, xpirdt
from cte
where rn = 1

O que significa que esta linha é a vencedora:
10948448    5/14/2015   <null>

Se, no entanto, você quiser que os nulos sejam considerados apenas se não houver datas de expiração, você pode usar nulls last (ou omita, pois é o padrão):
with cte as (
  select
    addrid, effectdt, xpirdt,
    row_number() over
        (partition by addrid order by effectdt desc, xpirdt nulls last) as rn
  from addrdata
)
select
  addrid, effectdt, xpirdt
from cte
where rn = 1

Significando que esse cara ganhou o prêmio:
10948448    5/14/2015   5/13/2015

Como isso usa row_number() você não perderá nenhuma linha - cada linha terá um número de linha. É só que, se houver empates verdadeiros, é um sorteio sobre qual linha é escolhida. No entanto, seu problema com datas de expiração nulas não deve causar problemas com essa abordagem.

-- editado 13/02/16 --

Acho que estou começando para entender seu problema, mas não tenho 100% de certeza. Eu incorporei trechos do seu código com a junção à esquerda com minha sugestão e a necessidade de ter datas de expiração nulas primeiro, e este é meu próximo crack:
with cte as (
  select
    addrid, effectdt, xpirdt,
    row_number() over 
        (partition by addrid order by effectdt desc, xpirdt nulls first) as rn
  from addrdata
)
select
  cte.addrid, effectdt, xpirdt
from
  mbr_person mb
  left join partyxref px on
    mb.nameid = px.nameid and
    px.reftype = 'COMM'
  left join cte on
    px.refkey = cte.addrid and
    cte.rn = 1

Supondo que isso não faça isso:
  1. Quando você diz que um XPIRDT nulo tem precedência, você quer dizer até mesmo em datas efetivas mais recentes ou é apenas um critério de desempate para o EFFECTDT mais recente? Se o último, então o que eu tenho deve funcionar. Se for o primeiro, precisamos mudar a ordem por na função analítica
  2. Estou totalmente adivinhando quando se trata da partyxref e mbr_person mesas. Se isso não resolver, talvez poste alguns dados de exemplo e a saída desejada para incluir essas duas tabelas ou mexa-se?