LAG and LEAD in SQL Server: Simple Examples
10a - LAG and LEAD (VERY SIMPLE version)
---------------------------------------------------------------------
No setup needed. This file creates its own small table.
LAG = look at the PREVIOUS row LEAD = look at the NEXT row
LAG(column) OVER (ORDER BY some_column) LEAD(column) OVER (ORDER BY some_column)
Run the sample database script first. Every query below was run on that data, and the Output under each query is the real result.
IF DB_ID('SqlLearningDb') IS NULL
CREATE DATABASE SqlLearningDb;
GO
USE SqlLearningDb;
GO
Small table: sales of one shop for 6 months
DROP TABLE IF EXISTS dbo.ShopSales;
CREATE TABLE dbo.ShopSales
(
SaleMonth INT, -- 1 = Jan, 2 = Feb ...
MonthName VARCHAR(10),
Amount INT
);
INSERT INTO dbo.ShopSales (SaleMonth, MonthName, Amount) VALUES
(1, 'Jan', 1000),
(2, 'Feb', 1500),
(3, 'Mar', 1200),
(4, 'Apr', 1800),
(5, 'May', 1700),
(6, 'Jun', 2000);
GO
SELECT * FROM dbo.ShopSales;
Messages(6 rows affected)
Output
| SaleMonth | MonthName | Amount |
| 1 | Jan | 1000 |
| 2 | Feb | 1500 |
| 3 | Mar | 1200 |
| 4 | Apr | 1800 |
| 5 | May | 1700 |
| 6 | Jun | 2000 |
LAG: previous month's amount
Jan has no previous month, so it shows NULL
SELECT MonthName,
Amount,
LAG(Amount) OVER (ORDER BY SaleMonth) AS PreviousMonth
FROM dbo.ShopSales;
Output
| MonthName | Amount | PreviousMonth |
| Jan | 1000 | NULL |
| Feb | 1500 | 1000 |
| Mar | 1200 | 1500 |
| Apr | 1800 | 1200 |
| May | 1700 | 1800 |
| Jun | 2000 | 1700 |
LEAD: next month's amount
Jun has no next month, so it shows NULL
SELECT MonthName,
Amount,
LEAD(Amount) OVER (ORDER BY SaleMonth) AS NextMonth
FROM dbo.ShopSales;
Output
| MonthName | Amount | NextMonth |
| Jan | 1000 | 1500 |
| Feb | 1500 | 1200 |
| Mar | 1200 | 1800 |
| Apr | 1800 | 1700 |
| May | 1700 | 2000 |
| Jun | 2000 | NULL |
LAG and LEAD together
SELECT MonthName,
LAG(Amount) OVER (ORDER BY SaleMonth) AS PreviousMonth,
Amount AS ThisMonth,
LEAD(Amount) OVER (ORDER BY SaleMonth) AS NextMonth
FROM dbo.ShopSales;
Output
| MonthName | PreviousMonth | ThisMonth | NextMonth |
| Jan | NULL | 1000 | 1500 |
| Feb | 1000 | 1500 | 1200 |
| Mar | 1500 | 1200 | 1800 |
| Apr | 1200 | 1800 | 1700 |
| May | 1800 | 1700 | 2000 |
| Jun | 1700 | 2000 | NULL |
Show 0 instead of NULL (third value = default)
SELECT MonthName,
Amount,
LAG(Amount, 1, 0) OVER (ORDER BY SaleMonth) AS PreviousMonth
FROM dbo.ShopSales;
Output
| MonthName | Amount | PreviousMonth |
| Jan | 1000 | 0 |
| Feb | 1500 | 1000 |
| Mar | 1200 | 1500 |
| Apr | 1800 | 1200 |
| May | 1700 | 1800 |
| Jun | 2000 | 1700 |
Go back 2 rows instead of 1 (second value = how many rows)
SELECT MonthName,
Amount,
LAG(Amount, 2) OVER (ORDER BY SaleMonth) AS TwoMonthsAgo
FROM dbo.ShopSales;
Output
| MonthName | Amount | TwoMonthsAgo |
| Jan | 1000 | NULL |
| Feb | 1500 | NULL |
| Mar | 1200 | 1000 |
| Apr | 1800 | 1500 |
| May | 1700 | 1200 |
| Jun | 2000 | 1800 |
Difference from last month (most common use of LAG)
SELECT MonthName,
Amount,
LAG(Amount) OVER (ORDER BY SaleMonth) AS PreviousMonth,
Amount - LAG(Amount) OVER (ORDER BY SaleMonth) AS Difference
FROM dbo.ShopSales;
Output
| MonthName | Amount | PreviousMonth | Difference |
| Jan | 1000 | NULL | NULL |
| Feb | 1500 | 1000 | 500 |
| Mar | 1200 | 1500 | -300 |
| Apr | 1800 | 1200 | 600 |
| May | 1700 | 1800 | -100 |
| Jun | 2000 | 1700 | 300 |
Did sales go Up or Down?
SELECT MonthName,
Amount,
CASE
WHEN Amount > LAG(Amount) OVER (ORDER BY SaleMonth) THEN 'UP'
WHEN Amount < LAG(Amount) OVER (ORDER BY SaleMonth) THEN 'DOWN'
ELSE '-'
END AS Trend
FROM dbo.ShopSales;
Output
| MonthName | Amount | Trend |
| Jan | 1000 | - |
| Feb | 1500 | UP |
| Mar | 1200 | DOWN |
| Apr | 1800 | UP |
| May | 1700 | DOWN |
| Jun | 2000 | UP |
Practice Questions
- Show each month with the NEXT month's name (use LEAD on MonthName).
- Show how much sales will change from this month to next month (use LEAD).
- Show the amount from 3 months ago.