Один из наиболее переносимых подходов — пронумеровать операции отдельно для каждого кли... — 25 июня 2026 г. в 15:55:01.635
Один из наиболее переносимых подходов — пронумеровать операции отдельно для каждого клиента: WITH ranked AS ( SELECT operation_id, client_id, operation_time, operation_type, amount, ROW_NUMBER() OVER ( PARTITION BY client_id ORDER BY operation_time DESC, operation_id DESC ) AS rn FROM client_operations ) SELECT operation_id, client_id, operation_time, operation_type, amount FROM ranked WHERE rn = 1 ORDER BY client_id; Результат: Клиент 101 12 | 24.06 16:40 | refund | -200 Клиент 102 22 | 24.06 12:00 | purchase | 700 Клиент 103 31 | 23.06 18:30 | purchase | 900 Поля в строке: operation_id | operation_time | operation_type | amount. PARTITION BY client_id создаёт отдельную нумерацию для каждого клиента. operation_time DESC ставит более поздние операции первыми. operation_id DESC разрешает равенство времени по условию задачи. Без него одна из равных строк всё равно получила бы номер 1, но порядок выбора не был бы определён. В PostgreSQL запрос можно записать короче: SELECT DISTINCT ON (client_id) operation_id, client_id, operation_time, operation_type, amount FROM client_operations ORDER BY client_id, operation_time DESC, operation_id DESC; DISTINCT ON — расширение PostgreSQL. Для решения, переносимого между разными СУБД, чаще используют оконную функцию. Почему соединение с MAX(operation_time) даст другой результат? WITH latest AS ( SELECT client_id, MAX(operation_time) AS latest_time FROM client_operations GROUP BY client_id ) SELECT o.* FROM client_operations AS o JOIN latest AS l ON l.client_id = o.client_id AND l.latest_time = o.operation_time; Для клиента 102 оно вернёт две строки, потому что обе имеют максимальное время. Это правильное решение, если нужны все операции, разделившие первое место, но не если нужна ровно одна строка. Практический вывод: сначала определите смысл слова «последняя». Нужна одна запись или все записи с максимальным временем? Если одна — задайте явный и обоснованный tie-breaker. В рабочей системе нельзя автоматически считать больший ID признаком более поздней операции, если это не гарантировано моделью данных. #УЦФОРС #SQL #PostgreSQL #АналитикаДанных #ОконныеФункции

