Reputation: 787
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:
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! :)
Upvotes: 1
Views: 2132
Reputation: 16377
I'm still not clear which record, in your example, you wanted, so let me give you some alternatives.
I gathered from your problem statement that you want the latest effective date of those available. Since there are ties involved, you cannot use max()
(as you've already stated), and row_number()
is the way to go:
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
The next part was where you lost me with the nulls... If your secondary sort is by expiration date and you want a null value to trump the latest expiration date, then you would order by the expiration date and put 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
Which means this row is the winner:
10948448 5/14/2015 <null>
If, however, you wanted nulls to be considered only if there are no expiration dates, you can use nulls last
(or omit it, as it is the default):
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
Meaning this guy has won the prize:
10948448 5/14/2015 5/13/2015
Since this uses row_number()
you will not lose any rows -- each row is guaranteed to have a row number. It's just that if there are true ties, then it's a toss-up as to which row is chosen. However, your issue with null expiration dates should not cause any problems with this approach.
-- edit 2/13/16 --
I think I'm starting to understand your issue, but I'm not 100% sure. I've incorporated snippets of your code with the left join with my suggestion, and the need to have null expiration dates first, and this is my next 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
Assuming this doesn't do it:
partyxref
and mbr_person
tables. If this doesn't cut it, maybe post some sample data and desired output for including those two tables, or fiddle it?Upvotes: 2