SQL Server: LAG Function

This Oracle tutorial explains how to use the SQL Server (Transact-SQL) LAG function with syntax and examples.

Description

In SQL Server (Transact-SQL), the LAG function is an analytic function that lets you query more than one row in a table at a time without having to join the table to itself. It returns values from a previous row in the table. To return a value from the next row, try using the LEAD function.

Syntax

The syntax for the LAG function in SQL Server (Transact-SQL) is:

LAG ( expression [, offset [, default] ] )
OVER ( [ query_partition_clause ] order_by_clause )

Parameters or Arguments

expression
An expression that can contain other built-in functions, but can not contain any analytic functions.
offset
Optional. It is the physical offset from the current row in the table. If this parameter is omitted, the default is 1.
default
Optional. It is the value that is returned if the offset goes out of the bounds of the table. If this parameter is omitted, the default is null.
query_partition_clause
Optional. It is used to partition the results into groups based on one or more expressions.
order_by_clause
Optional. It is used to order the data within each partition.

Applies To

The LAG function can be used in the following versions of SQL Server (Transact-SQL):

  • SQL Server 2017, SQL Server 2016, SQL Server 2014, SQL Server 2012

DDL/DML for Examples

If you want to follow along with this tutorial, get the DDL to create the tables and the DML to populate the data. Then try the examples in your own database!

Get DDL/DML

Example

The LAG function can be used in SQL Server (Transact-SQL).

Let’s look at an example. If we had an employees table that contained the following data:

employee_number last_name first_name salary dept_id
12009 Sutherland Barbara 54000 45
34974 Yates Fred 80000 45
34987 Erickson Neil 42000 45
45001 Parker Sally 57500 30
75623 Gates Steve 65000 30

And we ran the following SQL statement:

SELECT dept_id, last_name, salary,
LAG (salary,1) OVER (ORDER BY salary) AS lower_salary
FROM employees;

It would return the following result:

dept_id last_name salary lower_salary
45 Erickson 42000 NULL
45 Sutherland 54000 42000
30 Parker 57500 54000
30 Gates 65000 57500
45 Yates 80000 65000

In this example, the LAG function will sort in ascending order all of the salary values in the employees table and then return the salary that is 1 position lower in the result set since we used an offset of 1.

If we had used an offset of 2 instead, it would have returned the salary that is 2 salaries lower. If we had used an offset of 3, it would have returned the salary that is 3 lower….and so on.

Using Partitions

Now let’s look at a more complex example where we use a query partition clause to return the lower salary for each employee within their own department.

Enter the following SQL statement:

SELECT dept_id, last_name, salary,
LAG (salary,1) OVER (PARTITION BY dept_id ORDER BY salary) AS lower_salary
FROM employees;

It would return the following result:

dept_id last_name salary lower_salary
30 Parker 57500 NULL
30 Gates 65000 57500
45 Erickson 42000 NULL
45 Sutherland 54000 42000
45 Yates 80000 54000

In this example, the LAG function will partition the results by dept_id and then sort by salary as indicated by PARTITION BY dept_id ORDER BY salary. This means that the LAG function will only evaluate a salary value if the dept_id matches the current record’s dept_id. When a new dept_id is encountered, the LAG function will restart its calculations and use the appropriate dept_id partition.

As you can see, the 1st record in the result set has a value of NULL for the lower_salary because it is the first record for the partition where dept_id is 30 (sorted by salary) so there is no lower salary value. This is also true for the 3rd record where the dept_id is 45.