Oracle 11g R2 is in use. This is my source table:
ASSETNUM WONUM WODATE TYPE1 TYPE2 LOCATION
--------------------------------------------------------
W1 1001 2015-10-10 N N loc1
W1 1002 2015-10-02 Y N loc2
W1 1003 2015-10-04 Y N loc2
W1 1004 2015-10-05 N Y loc2
W1 1005 2015-10-07 N Y loc2
W2 2001 2015-10-11 N N loc1
W2 2002 2015-10-03 Y N loc2
W2 2003 2015-10-02 Y N loc2
W2 2004 2015-10-08 N Y loc3
W2 2005 2015-10-06 N Y loc3
http://sqlfiddle.com/#!4/8ee297/1
I want to write a query to get following data:
ASSETNUM LATEST LOCATION for LATEST_WODATE_FOR LATEST_WODATE_FOR
WODATE LATEST WODATE TYPE1=Y TYPE2=Y
----------------------------------------------------------------------------
W1 2015-10-10 loc1 2015-10-04 2015-10-07
W2 2015-10-11 loc1 2015-10-03 2015-10-08
I need a similar resultset with only one row for each unique value in ASSETNUM.
Any help would be appreciated!
Analytic functions to the rescue.
http://sqlfiddle.com/#!4/8ee297/4
select assetnum,
wodate,
wonum,
location,
last_type1_wodate,
last_type2_wodate
from(select assetnum,
wodate,
wonum,
location,
rank() over (partition by assetnum order by wodate desc) rnk_wodate,
max(case when type1 = 'Y' then wodate else null end)
over (partition by assetnum) last_type1_wodate,
max(case when type2 = 'Y' then wodate else null end)
over (partition by assetnum) last_type2_wodate
from t)
where rnk_wodate = 1
Walking through what that's doing
rank() over (partition by assetnum order by wodate desc)
takes all the rows for a particular assetnum
and sorts them by wodate
. The predicate on the outside where rnk_wodate = 1
returns just the most recent row. If there can be ties, you may want to use dense_rank
or row_number
in place of rank
depending on how you want ties to be handled.max(case when type1 = 'Y' then wodate else null end) over (partition by assetnum)
takes all the rows for a particular assetnum
and finds the value that maximizes the case
expression. That will be the last row where type1 = 'Y'
for that assetnum
.I think the conceptually easiest approach to this is to simply view your problem as 3 separate queries, each of which is doing a GROUP BY
to obtain some specific thing (the latest WODATE
, the latest WODATE
for Type1, and the latest WODATE
for Type2). These queries can easily be joined together to give you the output you want.
SELECT T.ASSETNUM, t1.LATEST_WODATE, T.LOCATION, t2.LATEST_WODATE_TYPE1,
t3.LATEST_WODATE_TYPE2
FROM T INNER JOIN
(
SELECT ASSETNUM, MAX(WODATE) AS LATEST_WODATE
FROM T
GROUP BY ASSETNUM
) t1
ON T.ASSETNUM = t1.ASSETNUM AND T.WODATE = t1.LATEST_WODATE
INNER JOIN
(
SELECT ASSETNUM, MAX(WODATE) AS LATEST_WODATE_TYPE1
FROM T
WHERE TYPE1 = 'Y'
GROUP BY ASSETNUM
) t2
ON T.ASSETNUM = t2.ASSETNUM
INNER JOIN
(
SELECT ASSETNUM, MAX(WODATE) AS LATEST_WODATE_TYPE2
FROM T
WHERE TYPE2 = 'Y'
GROUP BY ASSETNUM
) t3
ON T.ASSETNUM = t3.ASSETNUM
Click the link below for a running demo:
SQLFiddle
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With