LAST VALUE: примеры (SQL)
LAST_VALUE(scalar_expression OVER [PARTITION BY ] ORDER BY [ROWS/ RANGE ]): Same as scalar_expressionФункция LAST_VALUE в MS SQL Server
Функция LAST_VALUE является оконной функцией, которая возвращает последнее значение из упорядоченного набора строк в рамках окна, определяемого предложением OVER. Она применяется в аналитических запросах для получения данных из конечной строки заданной секции без использования самообъединений.
Функция используется, когда необходим доступ к значению из последней строки упорядоченного набора данных в рамках группы. Типичные сценарии включают вычисление разницы между текущим и последним значением в периоде, определение финального статуса или получение итоговой суммы нарастающим итогом.
Синтаксис:LAST_VALUE ( выражение ) OVER ( [ <аргументы_окна> ] )
Аргументы:
- выражение — столбец или вычисляемое выражение, значение которого возвращается из последней строки окна. Не может быть другой оконной функцией или агрегатной функцией.
- OVER ( [ аргументы_окна ] ) — определяет секционирование и упорядочение набора строк. Аргументы включают:
- PARTITION BY — делит результирующий набор на секции, к которым применяется функция. Необязательный аргумент.
- ORDER BY — определяет логический порядок строк в каждой секции. Обязателен для функции LAST_VALUE.
- ROWS/RANGE — ограничивает строки в рамках секции, указывая начальную и конечную точки окна. По умолчанию используется
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, что часто приводит к неожиданным результатам. Для получения истинного последнего значения обычно используютROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING.
Возвращаемое значение: Тип данных, идентичный типу переданного выражения.
Простые примеры использования
Пример 1: Базовое использование с ORDER BY и изменением рамки окна.
SELECT
месяц,
выручка,
LAST_VALUE(выручка) OVER (ORDER BY месяц) как ПоследняяЗначПоУмолчанию,
LAST_VALUE(выручка) OVER (ORDER BY месяц ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) как ИстинноеПоследнее
FROM (VALUES
('Янв', 100),
('Фев', 150),
('Мар', 200)
) as t(месяц, выручка);месяц | выручка | ПоследняяЗначПоУмолчанию | ИстинноеПоследнее ------|---------|---------------------------|------------------- Янв | 100 | 100 | 200 Фев | 150 | 150 | 200 Мар | 200 | 200 | 200
Пример 2: Использование с PARTITION BY для получения последнего значения в каждой группе.
SELECT
отдел,
сотрудник,
зарплата,
LAST_VALUE(зарплата) OVER (
PARTITION BY отдел
ORDER BY сотрудник
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) as ПоследняяЗПВОтделе
FROM (VALUES
('IT', 'Алексей', 50000),
('IT', 'Мария', 55000),
('HR', 'Иван', 45000),
('HR', 'Ольга', 47000)
) as t(отдел, сотрудник, зарплата);отдел | сотрудник | зарплата | ПоследняяЗПВОтделе ------|-----------|----------|-------------------- HR | Иван | 45000 | 47000 HR | Ольга | 47000 | 47000 IT | Алексей | 50000 | 55000 IT | Мария | 55000 | 55000
Похожие функции в MS SQL
FIRST_VALUE — возвращает первое значение в упорядоченном наборе. Применяется, когда требуется начальное значение, а не конечное.
LAG и LEAD — позволяют обращаться к данным из предыдущих или следующих строк относительно текущей на заданное смещение. Удобны для последовательного сравнения соседних строк, в то время как LAST_VALUE работает с границей всего окна.
MAX или MIN с оконным определением — при использовании с рамкой UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING могут дать аналогичный LAST_VALUE результат для вычисления экстремумов, но LAST_VALUE учитывает порядок, а не только значение.
Выбор функции: LAST_VALUE предпочтительнее, когда важен именно порядок строк и значение из конкретной позиции (последней). LAG/LEAD — для доступа к соседним строкам. FIRST_VALUE — для доступа к первой строке. Агрегатные функции — когда нужно именно максимальное или минимальное значение, независимо от порядка.
Аналоги в других СУБД
PostgreSQL, Oracle: Поддерживают идентичный синтаксис LAST_VALUE с теми же особенностями работы с рамками окна.
-- PostgreSQL/Oracle SELECT id, value, LAST_VALUE(value) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) FROM sample_table;
MySQL (с версии 8.0): Также поддерживает функцию LAST_VALUE. Поведение аналогично.
-- MySQL 8.0 SELECT id, value, LAST_VALUE(value) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) last_val FROM sample_table;
SQLite: Не имеет встроенной LAST_VALUE. Альтернатива — использование агрегатной функции MAX() с оконным определением или подзапрос.
-- SQLite (эмуляция через MAX) SELECT id, value, MAX(value) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as last_val FROM sample_table;
Основное отличие между реализациями — это возможность использования ROWS/RANGE и производительность. В MS SQL, PostgreSQL и Oracle семантика очень близка. В MySQL до версии 8.0 оконные функции отсутствовали.
Типичные ошибки
Ошибка 1: Использование ORDER BY без указания правильной рамки окна, приводящее к возврату текущего значения, а не последнего.
-- Неправильно SELECT месяц, выручка, LAST_VALUE(выручка) OVER (ORDER BY месяц) as Последняя FROM продажи; -- Для каждой строки возвращается значение выручки из текущей строки, а не из последней в наборе.
Ошибка 2: Попытка использования в WHERE или HAVING, что запрещено для оконных функций.
-- Ошибка SELECT месяц, выручка FROM продажи WHERE LAST_VALUE(выручка) OVER (ORDER BY месяц) > 1000; -- Так нельзя -- Оконные функции допускаются только в SELECT или ORDER BY.
Ошибка 3: Неоднозначное ORDER BY, приводящее к недетерминированным результатам, если несколько строк имеют одинаковые значения порядка.
SELECT id, группа, значение, LAST_VALUE(значение) OVER (PARTITION BY группа ORDER BY id) as последнее FROM таблица; -- Если в одной группе несколько строк с одинаковым id, результат может быть непредсказуемым.
Изменения в последних версиях
В MS SQL Server 2012 произошло введение поддержки оконных функций, включая LAST_VALUE. С тех пор существенных изменений в синтаксисе или базовом поведении функции не было.
Основные улучшения связаны с оптимизацией выполнения оконных функций в целом в более новых версиях SQL Server (2016, 2019, 2022), что повышает производительность запросов с LAST_VALUE, особенно при использовании индексов, соответствующих порядку в предложении OVER.
В версии SQL Server 2022 продолжена работа над улучшением обработки оконных функций в пакетном режиме для сценариев с большими объемами данных.
Расширенные примеры
Пример 1: Определение финального статуса в цепочке событий для каждого объекта.
WITH События AS (
SELECT 1 as object_id, '2023-01-01' as дата, 'Создан' as статус
UNION ALL SELECT 1, '2023-01-02', 'В работе'
UNION ALL SELECT 1, '2023-01-03', 'Завершен'
UNION ALL SELECT 2, '2023-01-01', 'Создан'
UNION ALL SELECT 2, '2023-01-05', 'В работе'
)
SELECT DISTINCT
object_id,
LAST_VALUE(статус) OVER (
PARTITION BY object_id
ORDER BY дата
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) as итоговый_статус
FROM События;object_id | итоговый_статус ----------|---------------- 1 | Завершен 2 | В работе
Пример 2: Расчет нарастающего итога с выводом последнего значения итога как общей суммы.
SELECT
месяц,
выручка,
SUM(выручка) OVER (ORDER BY месяца ROWS UNBOUNDED PRECEDING) as нарастающий_итог,
LAST_VALUE(выручка) OVER (
ORDER BY месяца ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) as общая_выручка_через_LAST,
SUM(выручка) OVER () as общая_выручка_через_SUM
FROM продажи
ORDER BY месяца;Пример 3: Использование с IGNORE NULLS (доступно с SQL Server 2022). Получение последнего непустого значения.
-- Только для SQL Server 2022 и новее SELECT дата, показатель, LAST_VALUE(показатель) IGNORE NULLS OVER (ORDER BY дата) as последнее_непустое FROM временной_ряд;
Пример 4: Комбинирование с другими оконными функциями для сложной аналитики.
SELECT
отдел,
сотрудник,
продажи,
ROW_NUMBER() OVER (PARTITION BY отдел ORDER BY продажи DESC) as место_в_отделе,
LAST_VALUE(сотрудник) OVER (
PARTITION BY отдел
ORDER BY продажи
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) as сотрудник_с_мин_продажами
FROM результаты_квартала;