Oracle: getting maximum value of a group? Oracle: getting maximum value of a group? sql sql

Oracle: getting maximum value of a group?


I'd tend to use analytic functions

SELECT monitor_id,       host_name,       calibration_date,       value  FROM (SELECT b.monitor_id,               b.host_name,               a.calibration_date,               a.value,               rank() over (partition by b.monitor_id order by a.calibration_date desc) rnk          FROM table_name a,               table_name2 b         WHERE a.some_key = b.some_key) WHERE rnk = 1

You could also use correlated subqueries though that will be less efficient

SELECT monitor_id,       calibration_date,       value  FROM table_name a WHERE a.calibration_date = (SELECT MAX(b.calibration_date)                               FROM table_name b                              WHERE a.monitor_id = b.monitor_id)


My personal preference is this:

SELECT DISTINCT       monitor_id      ,MAX(calibration_date)       OVER (PARTITION BY monitor_id)       AS latest_calibration_date      ,FIRST_VALUE(value)       OVER (PARTITION BY monitor_id             ORDER BY calibration_date DESC)       AS latest_valueFROM mytable;

A variation would be to use the FIRST_VALUE syntax for latest_calibration_date as well. Either way works.


The window functions solution should be the most efficient and result in only one table or index scan. The one I am posting here i think wins some points for being intuitive and easy to understand. I tested on SQL server and it performed 2nd to window functions, resulting in two index scans.

SELECT T1.monitor_id, T1.calibration_date, T1.valueFROM someTable AS T1WHERE NOT EXISTS (    SELECT *     FROM someTable AS T2    WHERE T2.monitor_id = T1.monitor_id AND T2.value > T1.value) GROUP BY T1.monitor_id, T1.calibration_date, T1.value

And just for the heck of it, here's another one along the same lines, but less performing (63% cost vs 37%) than the other (again in sql server). This one uses a Left Outer Join in the execution plan where as the first one uses an Anti-Semi Merge Join:

SELECT T1.monitor_id, T1.calibration_date, T1.valueFROM someTable AS T1LEFT JOIN someTable AS T2 ON T2.monitor_id = T1.monitor_id AND T2.value > T1.valueWHERE T2.monitor_id IS NULLGROUP BY T1.monitor_id, T1.calibration_date, T1.value