-----------------------------------------------------------
chan1   |chan2  |chan3  | captureTime       |id
-----------------------------------------------------------
20  |21 |25 | 2011-10-11 00:00:00   |1
-----------------------------------------------------------
21  |18 |19 | 2011-10-11 00:01:00   |1
-----------------------------------------------------------
                ....
                ....
                ....
-----------------------------------------------------------
20  |25 |21 | 2011-10-11 00:15:00   |1
-----------------------------------------------------------
21  |18 |14 | 2011-10-11 00:16:00   |1
                ....
                ....
                ....
-----------------------------------------------------------
15  |26 |23 | 2011-10-11 23:58:00   |1
-----------------------------------------------------------
17  |14 |32 | 2011-10-11 23:59:00   |1

The table store chan1,chan2 and chan3 value every one minute. I want to get the maximum & minimum values for every 10 minutes and also have the corresponding the captureTime for min/max values.

Based on those requirments, How to write the sql query? Thanks!

Dani AI

Generated

The requirement can be read two ways: (A) get per-channel min/max for each 10‑minute window and the captureTime when those extremes occurred, or (B) get a single overall min/max across chan1/chan2/chan3 per 10‑minute window and the time when that value appeared. ’s sample data fits either interpretation. ’s idea (using GREATEST()) targets the overall-across-channels case but the use of SUBSTR(...) to form 10‑minute buckets is brittle and the correlated WHERE in the example references an alias that isn’t defined in the outer query.

Per-channel pattern (works on older MySQL and is straightforward): first aggregate to get MIN/MAX per 10‑minute bucket, then find the corresponding captureTime(s) with a correlated subquery (use MIN(captureTime) to pick the earliest if there are ties). Example pattern — repeat the chan1 subselect for chan2/chan3:

SELECT agg.bucket,
       agg.min_c1,
       (SELECT MIN(t.captureTime) FROM myTable t
        WHERE FROM_UNIXTIME(UNIX_TIMESTAMP(t.captureTime) DIV 600 * 600) = agg.bucket
          AND t.chan1 = agg.min_c1) AS min_c1_time,
       agg.max_c1,
       (SELECT MIN(t.captureTime) FROM myTable t
        WHERE FROM_UNIXTIME(UNIX_TIMESTAMP(t.captureTime) DIV 600 * 600) = agg.bucket
          AND t.chan1 = agg.max_c1) AS max_c1_time
FROM (
  SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(captureTime) DIV 600 * 600) AS bucket,
         MIN(chan1) AS min_c1, MAX(chan1) AS max_c1
  FROM myTable
  GROUP BY bucket
) AS agg
ORDER BY agg.bucket;

Overall-across-channels pattern (UNION ALL unpivot): flatten the three channels into (bucket, value, captureTime), aggregate MIN/MAX per bucket, then join back to the flattened rows to get the times. That approach is simple and exact if the goal is a single min/max per bucket regardless of which channel it came from.

Performance and correctness tips:

  • Compute the 10‑minute bucket once (either a persisted/generated column or a derived column in a temp table) to avoid repeating FROM_UNIXTIME/UNIX_TIMESTAMP calls.
  • Index the bucket or captureTime for large tables.
  • Decide tie-break rules (earliest time, specific channel) and use MIN(captureTime) or an extra ORDER BY in a LIMIT 1 subquery to enforce it.
  • Be aware of server time zone when using UNIX_TIMESTAMP on DATETIME.
select greatest(t1.chan1,t1.chan2,t1.chan3), captureTime
from myTable t1
where greatest(t1.chan1,t1.chan2,t1.chan3) = (
  select max(greatest(t2.chan1, t2.chan2, t2.chan3))
  from myTable t2
  group by substr(t2.captureTime, 1, 15)
)
and substr(t1.captureTime, 1, 15 ) = substr( t2.captureTime, 1, 15)

Lots of query optimization needed, I presume.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.