2

Let's say I have a table MyTable with the columns Id, NumericValue and UTCTimestamp. I'm trying to group the results of my table MyTable by the hour of their timestamp and return the maximum NumericValuefor each group with its associated timestamp as well as the minimum NumericValue for each group with its associated timestamp value.

For now, I'm able to achieve the first part of my problem with the following query:

SELECT 
    HOUR(t.UTCTimestamp) AS `Hour`, 
    t.NumericValue AS MaximumValue,
    t.UTCTimestamp AS MaximumValueTime
FROM MyTable t
INNER JOIN (
    SELECT HOUR(t2.UTCTimestamp) AS `Hour`, MAX(t2.NumericValue) AS NumericValue
    FROM MyTable t2
    GROUP BY HOUR(t2.UTCTimestamp)
) maxNumericValue ON HOUR(t.UTCTimestamp) = maxNumericValue.`Hour` AND t.NumericValue = maxNumericValue.NumericValue
GROUP BY HOUR(t.UTCTimestamp);

Which was inspired by this answer.

Here's an MVCE.

How could I also show the minimum value for each group as well as the timestamp associated to it?

actaram
  • 2,038
  • 4
  • 28
  • 49

3 Answers3

2

Starting from MySQL 8.0 you could use ROW_NUMBER:

WITH cte AS (
  SELECT *,ROW_NUMBER() OVER(PARTITION BY HOUR(UTCTimestamp) 
                              ORDER BY UTCTimestamp ASC)  AS rn
          ,ROW_NUMBER() OVER(PARTITION BY HOUR(UTCTimestamp) 
                              ORDER BY UTCTimestamp DESC) AS rn2
  FROM MyTable
)
SELECT HOUR(c1.UTCTimestamp),
     c1.ID, c1.NumericValue, c1.UTCTimestamp,  -- min row
     c2.ID, c2.NumericValue, c2.UTCTimestamp   -- max row
FROM cte c1
JOIN cte c2
  ON HOUR(c1.UTCTimestamp) = HOUR(c2.UTCTimestamp)
  AND c1.rn=1
  AND c2.rn2=1
ORDER BY HOUR(c1.UTCTimestamp) ASC;

DBFiddle Demo

Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
  • 1
    Thank you for your answer and sorry for not being specific enough. I'm running in `mysql-5.6`, but I'll keep this solution in mind for the future. – actaram May 03 '18 at 17:43
1

Apply the same technique but with minimum:

select a.*, b.MinimumValueTime from (
SELECT 
    HOUR(t.UTCTimestamp) AS `Hour`, 
    t.NumericValue AS MaximumValue,
    t.UTCTimestamp AS MaximumValueTime
FROM MyTable t
INNER JOIN (
    SELECT HOUR(t2.UTCTimestamp) AS `Hour`, MAX(t2.NumericValue) AS NumericValue
    FROM MyTable t2
    GROUP BY HOUR(t2.UTCTimestamp)
) maxNumericValue ON HOUR(t.UTCTimestamp) = maxNumericValue.`Hour` AND t.NumericValue = maxNumericValue.NumericValue
GROUP BY HOUR(t.UTCTimestamp))a
join
(
SELECT 
    HOUR(t.UTCTimestamp) AS `Hour`, 
    t.NumericValue AS MinimumValue,
    t.UTCTimestamp AS MinimumValueTime
FROM MyTable t
INNER JOIN (
    SELECT HOUR(t2.UTCTimestamp) AS `Hour`, MIN(t2.NumericValue) AS NumericValue
    FROM MyTable t2
    GROUP BY HOUR(t2.UTCTimestamp)
) minNumericValue ON HOUR(t.UTCTimestamp) = minNumericValue.`Hour` AND t.NumericValue = minNumericValue.NumericValue
GROUP BY HOUR(t.UTCTimestamp))b on a.hour=b.hour
Daniel Marcus
  • 2,686
  • 1
  • 7
  • 13
1

You can join to MyTable twice (and only use one aggregating subquery)

SELECT bounds.`Hour`
    , minT.NumericValue AS MinValue
    , minT.UTCTimestamp AS MinTime
    , maxT.NumericValue AS MaximumValue
    , maxT.UTCTimestamp AS MaximumValueTime
FROM (
    SELECT HOUR(t2.UTCTimestamp) AS `Hour`
         , MAX(t2.NumericValue) AS maxValue
         , MIN(t2.NumericValue) AS minValue
    FROM MyTable t2
    GROUP BY HOUR(t2.UTCTimestamp)
) bounds 
LEFT JOIN MyTable minT ON bounds.`Hour` = HOUR(minT.UTCTimestamp)
   AND bounds.minValue = minT.NumericValue
LEFT JOIN MyTable maxT ON bounds.`Hour` = HOUR(maxT.UTCTimestamp)
   AND bounds.maxValue = maxT.NumericValue
;
Uueerdo
  • 15,723
  • 1
  • 16
  • 21