Oracle Join Condition with Top 1

时间:2016-02-12 19:29:46

标签: sql oracle oracle11g greatest-n-per-group

I've tried to find a solution to this including the use of the row_number() method within my join, but somehow can't get the desired outcome.

The issue I'm having right now is based on the fact that I have some records from the join table that have multiple instances (1 to many) with the same criteria which is causing duplicates, so even though I thought I could use a min() or max() on a date, the cases where I have the same EffectDT come out twice.

In addition to this, if I have instances where I don't have an "active" record (XPIRDT IS NOT NULL), I need to pull the expired record, so would I use "OR" statement or simply perform another join to get the expired record in the event the first join doesn't produce any record and have a case condition to evaluate the value before display?

So here's an instance of sample data I'm dealing with:

SAMPLE DATA

So the following with the above data sample still produces 2 records, which I can eliminate one by evaluating the expiry date, BUT will present problems if all the records are expired so won't retrieve anything.

 LEFT OUTER JOIN PARTYXREF
      ON MBR_PERSON.NAMEID = PARTYXREF.NAMEID
     AND PARTYXREF.REFTYPE LIKE 'COMM'
 LEFT JOIN (
                SELECT *
                FROM ADDRDATA TMP
                WHERE TMP.ADDRTYPE = '2'
                AND TMP.EFFECTDT = (SELECT MAX(EFFECTDT) FROM ADDRDATA TMP2 WHERE TMP2.ADDRID = TMP.ADDRID)
             )  MBR_ADDR
       ON PARTYXREF.REFKEY = MBR_ADDR.ADDRID  

I've also tried using the following within my "JOIN" statement, however I somehow can't make use of the joining key (REFKEY) within where I have the value hardcoded here, so this actually does work, but can't seem to incorporate in the join statement.

SELECT ADDR.*
FROM (SELECT tmp.*, row_number() OVER (ORDER BY XPIRDT DESC) AS SEQNUM
        FROM ADDRDATA tmp
        WHERE tmp.ADDRTYPE = '2'
          AND tmp.ADDRID = 10948448
       ) ADDR
WHERE SEQNUM = 1

I've wasted one hour too many on this, so I need someone else outlook please! :)

1 个答案:

答案 0 :(得分:1)

我仍然不清楚你的例子中你想要哪条记录,所以让我给你一些选择。

我从你的问题陈述中收集到你想要的最新生效日期。由于涉及到关系,您无法使用max()(正如您已经说明的那样),row_number()是可行的方法:

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

下一部分是你丢失我的空值...如果你的二级排序是到期日,你想要一个空值来胜过最新的到期日期,那么你将在到期日期前订购并放{{ 1}}:

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

但是,如果您希望仅在没有到期日期时考虑空值,则可以使用10948448 5/14/2015 <null> (或省略它,因为它是默认值):

nulls last

这个家伙已经获奖了:

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

由于这使用10948448 5/14/2015 5/13/2015 ,因此不会丢失任何行 - 每行都保证有行号。只是如果存在真正的联系,那么选择哪一行就是一个折腾。但是,您的null到期日期问题不应该导致此方法出现任何问题。

- 编辑2/13/16 -

我认为我开始了解您的问题,但我并非100%肯定。我已经将你的代码片段与我的建议中的左连接合并,并且首先需要有空的到期日期,这是我的下一个裂缝:

row_number()

假设没有这样做:

  1. 当你说一个空的XPIRDT优先时 - 你的意思是甚至在最近的生效日期,或者它只是最近的EFFECTDT的决胜局?如果是后者,那么我应该有所作为。如果是前者,那么我们需要在分析函数中按顺序切换
  2. 我完全猜测涉及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 partyxref表。如果这没有削减它,可能会发布一些样本数据和所需的输出以包含这两个表格,或者将其翻转过来?