Skip to main content

Window Value Functions

Value functions let you access data from other rows in the result set without self-joins, enabling time series analysis and comparisons.

LAG — Previous Row Value

Access a value from the previous row.

LAG(column, offset, default) OVER (ORDER BY ...)

LEAD — Next Row Value

Access a value from the next row.

LEAD(column, offset, default) OVER (ORDER BY ...)

Month-over-Month Analysis

SELECT
*,
CurrentMonthSales - PreviousMonthSales AS MoM_Change,
ROUND(
CAST((CurrentMonthSales - PreviousMonthSales) AS FLOAT)
/ PreviousMonthSales * 100, 1
) AS MoM_Pct
FROM (
SELECT
MONTH(OrderDate) AS OrderMonth,
SUM(Sales) AS CurrentMonthSales,
LAG(SUM(Sales)) OVER (ORDER BY MONTH(OrderDate)) AS PreviousMonthSales
FROM Sales.Orders
GROUP BY MONTH(OrderDate)
) AS MonthlySales;

Customer Loyalty — Days Between Orders

SELECT
CustomerID,
AVG(DaysUntilNextOrder) AS AvgDays,
RANK() OVER (ORDER BY COALESCE(AVG(DaysUntilNextOrder), 999999)) AS LoyaltyRank
FROM (
SELECT
CustomerID,
OrderDate,
LEAD(OrderDate) OVER (PARTITION BY CustomerID ORDER BY OrderDate) AS NextOrder,
DATEDIFF(day, OrderDate,
LEAD(OrderDate) OVER (PARTITION BY CustomerID ORDER BY OrderDate)
) AS DaysUntilNextOrder
FROM Sales.Orders
) t
GROUP BY CustomerID;

FIRST_VALUE & LAST_VALUE

SELECT
OrderID, ProductID, Sales,
FIRST_VALUE(Sales) OVER (
PARTITION BY ProductID ORDER BY Sales
) AS LowestSales,
LAST_VALUE(Sales) OVER (
PARTITION BY ProductID ORDER BY Sales
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
) AS HighestSales,
Sales - FIRST_VALUE(Sales) OVER (
PARTITION BY ProductID ORDER BY Sales
) AS DiffFromLowest
FROM Sales.Orders;
LAST_VALUE requires a frame clause

By default, the frame ends at the current row, so LAST_VALUE returns the current row's value. Always specify ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING to get the actual last value.

Summary

FunctionReturnsDefault Frame
LAG(col, n)Value from n rows beforeN/A
LEAD(col, n)Value from n rows afterN/A
FIRST_VALUE(col)First value in windowUses frame
LAST_VALUE(col)Last value in windowNeeds explicit frame