Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple Query to Grab Max Value for each ID

OK I have a table like this:

ID     Signal    Station    OwnerID
111     -120      Home       1
111     -130      Car        1
111     -135      Work       2
222     -98       Home       2
222     -95       Work       1
222     -103      Work       2

This is all for the same day. I just need the Query to return the max signal for each ID:

ID    Signal    Station    OwnerID
111   -120      Home        1
222   -95       Work        1

I tried using MAX() and the aggregation messes up with the Station and OwnerID being different for each record. Do I need to do a JOIN?

like image 833
Nick Sinas Avatar asked Apr 16 '09 12:04

Nick Sinas


2 Answers

Something like this? Join your table with itself, and exclude the rows for which a higher signal was found.

select cur.id, cur.signal, cur.station, cur.ownerid
from yourtable cur
where not exists (
    select * 
    from yourtable high 
    where high.id = cur.id 
    and high.signal > cur.signal
)

This would list one row for each highest signal, so there might be multiple rows per id.

like image 148
Andomar Avatar answered Sep 29 '22 10:09

Andomar


You are doing a group-wise maximum/minimum operation. This is a common trap: it feels like something that should be easy to do, but in SQL it aggravatingly isn't.

There are a number of approaches (both standard ANSI and vendor-specific) to this problem, most of which are sub-optimal in many situations. Some will give you multiple rows when more than one row shares the same maximum/minimum value; some won't. Some work well on tables with a small number of groups; others are more efficient for a larger number of groups with smaller rows per group.

Here's a discussion of some of the common ones (MySQL-biased but generally applicable). Personally, if I know there are no multiple maxima (or don't care about getting them) I often tend towards the null-left-self-join method, which I'll post as no-one else has yet:

SELECT reading.ID, reading.Signal, reading.Station, reading.OwnerID
FROM readings AS reading
LEFT JOIN readings AS highersignal
    ON highersignal.ID=reading.ID AND highersignal.Signal>reading.Signal
WHERE highersignal.ID IS NULL;
like image 41
bobince Avatar answered Sep 29 '22 10:09

bobince