开发者

Oracle query needs to return the highest date from result

I have a really big query in which makes some troubles for me because one join can return several rows. I only want the latest row (identified by a date field) in this result set, but I cant seem to put together the correct q开发者_开发知识库uery to make it work.

The query I need MAX date from is:

SELECT custid,reason,date FROM OPT opt WHERE opt.custid = 167043;

Teh custid is really found through a join, but for simplicity I've added it to the where clause here. This query produces the following result:

custid    grunn       date
167043  "Test 1"    19.10.2005 12:33:18
167043  "Test 2"    28.11.2005 16:23:35
167043  "Test 3"    14.06.2010 15:43:16

How can I retrieve only one record from this resultset? And that record is the one with the highest date? Ultimately Im putting this into a big query which does alot of joins, so hopefully I can use this example into my bigger query.


You can do this:

SELECT * FROM
( SELECT custid,reason,date FROM OPT opt WHERE opt.custid = 167043
  ORDER BY date DESC
) 
WHERE ROWNUM = 1;


You can solve it by using analytic functions. Try something like this:

select custid 
      ,reason
      ,date
  from (select custid 
              ,reason
              ,date
              ,row_number() over(partition by cust_id order by date desc) as rn
         from opt)
 where rn = 1;

This is how it works: The resultset is divided into groups of cust_id (partition by). In each group, the rows will be sorted by the date column in descending order (order by). Each row within the group will be assigned a sequence number (row_number) from 1 to N. This way the row with the highest value for date will be assigned 1, the second latest 2, third latest 3 etc..

Finally, I just pick the rows with nr = 1, which basically filters out the other rows.


Or another way using the LAST function in its aggregate form.

with my_source_data as (
  select 167043 as custid, 'Test 1' as reason, date '2010-10-01' as the_date from dual union  all
  select 167043 as custid, 'Test 2' as reason, date '2010-10-02' as the_date from dual union  all
  select 167043 as custid, 'Test 3' as reason, date '2010-10-03' as the_date from dual union  all
  select 167044 as custid, 'Test 1' as reason, date '2010-10-01' as the_date from dual
)
    select 
      custid,
      max(reason) keep (dense_rank last order by the_date) as reason,
      max(the_date)
    from my_source_data
    group by custid

I find this quite useful as it rolls the process of finding the last row and the value all into one. The use of MAX (or another aggregate function such as MIN) in case that the combination of the grouping and the order by is not deterministic.

This function will basically take the contents of the column based on the grouping, order it by the ordering given then take the last value.


rather than using row_number() I think it's better to select what you actually want to select (e.g. the last date)

SELECT custid
,      reason
,      date
from
(
    SELECT custid
    ,      reason
    ,      date
    ,      max(opt.date) over (partition by opt.custid order by opt.date) last_date 
    FROM   OPT opt 
    WHERE  opt.custid = 167043;
)
where  date = last_date


both solutions with ROW_NUMBER and KEEP are good. I would tend to prefer ROW_NUMBER when retrieving a large number of columns, and keep KEEP for one or two columns, otherwise you will have to deal with duplicates and the statement will get pretty unreadable.

For a small number of columns however, KEEP should perform better

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜