min_by

Returns a value from the row with the minimum comparison key.

Syntax

min_by(<value>, <key>)

Arguments

ArgumentTypeDescription
<value>Any typeExpression to return from the selected row. May be NULL.
<key>Any type except anyExpression used to select the row. NULL keys are ignored.

Returns

Returns the same type as <value>. Returns NULL if there is no non-NULL key. If keys tie, any tied row may be selected.

Examples

Keep the details of the fastest request

Find the fastest request per service and retain its ID and status together in one object.

VALUES
    ('checkout', 'req-101', 200, 95), ('checkout', 'req-102', 504, 1200),
    ('catalog', 'req-201', 200, 25), ('catalog', 'req-202', 200, 140)
SELECT $0 AS service, $1 AS request_id, $2 AS status, $3 AS latency_ms
GROUP BY service
AGGREGATE min_by({'request_id': request_id, 'status': status}, latency_ms) AS request
ORDER BY service
+----------+---------------------------------------+
| service  | request                               |
+----------+---------------------------------------+
| catalog  | {"request_id":"req-201","status":200} |
| checkout | {"request_id":"req-101","status":200} |
+----------+---------------------------------------+

Find the first acquisition channel

Choose the channel on the earliest event for each buyer, even when events arrive out of order.

VALUES
    ('buyer-17', '2026-06-01T10:05:00Z', 'email'),
    ('buyer-17', '2026-06-01T09:00:00Z', 'search'),
    ('buyer-42', '2026-06-01T11:00:00Z', 'referral')
SELECT $0 AS buyer_id, $1::timestamp AS event_time, $2 AS channel
GROUP BY buyer_id
AGGREGATE min_by(channel, event_time) AS first_channel
ORDER BY buyer_id
+----------+---------------+
| buyer_id | first_channel |
+----------+---------------+
| buyer-17 | search        |
| buyer-42 | referral      |
+----------+---------------+