Bird
Raised Fist0
PostgreSQLquery~5 mins

LAG and LEAD for row comparison in PostgreSQL

Choose your learning style10 modes available
Introduction

LAG and LEAD help you look at data from other rows in the same table. This is useful to compare values between rows easily.

To find the difference between a current row and the previous row, like daily sales changes.
To compare a value with the next row, such as checking if a stock price went up or down.
To see trends over time by comparing each row with the one before or after.
To find gaps or jumps in data by looking at neighboring rows.
To create reports that show changes between rows without complicated joins.
Syntax
PostgreSQL
LAG(column_name, offset, default_value) OVER (PARTITION BY partition_column ORDER BY order_column)
LEAD(column_name, offset, default_value) OVER (PARTITION BY partition_column ORDER BY order_column)

LAG looks at a previous row's value.

LEAD looks at a next row's value.

Offset is how many rows back or forward to look (default is 1).

Default value is used if there is no row to look at.

Examples
This shows sales and the previous day's sales for comparison.
PostgreSQL
SELECT sales, LAG(sales) OVER (ORDER BY date) AS prev_sales FROM sales_data;
This shows the price and the next day's price, using 0 if no next day exists.
PostgreSQL
SELECT date, price, LEAD(price, 1, 0) OVER (ORDER BY date) AS next_price FROM stock_prices;
This looks two rows back in the same department to compare salaries.
PostgreSQL
SELECT employee, salary, LAG(salary, 2) OVER (PARTITION BY department ORDER BY employee) AS salary_two_before FROM employees;
Sample Program

This example creates a sales table and shows each day's sales, the previous day's sales, and the next day's sales for easy comparison.

PostgreSQL
CREATE TABLE sales_data (date DATE, sales INT);
INSERT INTO sales_data VALUES
('2024-01-01', 100),
('2024-01-02', 150),
('2024-01-03', 130),
('2024-01-04', 170);

SELECT date, sales,
       LAG(sales) OVER (ORDER BY date) AS prev_sales,
       LEAD(sales) OVER (ORDER BY date) AS next_sales
FROM sales_data;
OutputSuccess
Important Notes

If there is no previous or next row, LAG or LEAD returns NULL or the default value you set.

Always use ORDER BY inside OVER() to define the row order for comparison.

You can use PARTITION BY to restart the comparison for groups, like departments or categories.

Summary

LAG and LEAD let you peek at other rows to compare values easily.

Use ORDER BY to control which rows are compared.

They help find trends, changes, or gaps in your data without complex joins.

Practice

(1/5)
1. What is the main purpose of the LAG function in PostgreSQL?
easy
A. To sort rows in ascending order
B. To access data from the next row in the same result set
C. To delete duplicate rows
D. To access data from a previous row in the same result set

Solution

  1. Step 1: Understand LAG function behavior

    The LAG function returns the value from a previous row based on the current row's position.
  2. Step 2: Compare with other options

    LEAD accesses the next row, sorting and deleting duplicates are unrelated to LAG.
  3. Final Answer:

    To access data from a previous row in the same result set -> Option D
  4. Quick Check:

    LAG = previous row data access [OK]
Hint: LAG looks backward, LEAD looks forward in rows [OK]
Common Mistakes:
  • Confusing LAG with LEAD
  • Thinking LAG sorts rows
  • Assuming LAG deletes duplicates
2. Which of the following is the correct syntax to use LEAD to get the next row's salary ordered by employee_id?
easy
A. LEAD(salary) OVER (ORDER BY employee_id)
B. LEAD(salary ORDER BY employee_id)
C. LEAD(salary) ORDER BY employee_id
D. LEAD(ORDER BY salary) OVER (employee_id)

Solution

  1. Step 1: Recall correct LEAD syntax

    The correct syntax uses LEAD(column) OVER (ORDER BY column) to specify the column and ordering.
  2. Step 2: Check each option

    LEAD(salary) OVER (ORDER BY employee_id) matches the correct syntax; others misuse parentheses or clause order.
  3. Final Answer:

    LEAD(salary) OVER (ORDER BY employee_id) -> Option A
  4. Quick Check:

    LEAD(column) OVER (ORDER BY column) [OK]
Hint: LEAD/LAG need OVER with ORDER BY inside parentheses [OK]
Common Mistakes:
  • Placing ORDER BY outside OVER clause
  • Missing parentheses around ORDER BY
  • Putting ORDER BY inside function parameters
3. Given the table sales with columns month and revenue, what will this query return?
SELECT month, revenue, LAG(revenue) OVER (ORDER BY month) AS prev_revenue FROM sales;
medium
A. Each row shows only current month revenue
B. Each row shows current month revenue and next month's revenue
C. Each row shows current month revenue and previous month's revenue
D. Query will cause a syntax error

Solution

  1. Step 1: Understand LAG with ORDER BY month

    The LAG(revenue) returns the revenue from the previous month ordered by month.
  2. Step 2: Interpret query output

    Each row shows current month revenue and previous month's revenue in prev_revenue. The first row's prev_revenue will be NULL.
  3. Final Answer:

    Each row shows current month revenue and previous month's revenue -> Option C
  4. Quick Check:

    LAG = previous row value [OK]
Hint: LAG returns previous row's value based on ORDER BY [OK]
Common Mistakes:
  • Confusing LAG with LEAD
  • Expecting next month's revenue instead
  • Thinking query causes error
4. Identify the error in this query:
SELECT employee_id, salary, LEAD(salary) ORDER BY employee_id FROM employees;
medium
A. ORDER BY should be inside LEAD() function
B. Missing OVER() clause for LEAD function
C. LEAD cannot be used with salary column
D. employee_id must be in GROUP BY clause

Solution

  1. Step 1: Check LEAD function syntax

    LEAD requires an OVER() clause to specify ordering and partitioning.
  2. Step 2: Analyze query structure

    The query uses LEAD(salary) without OVER(), causing a syntax error.
  3. Final Answer:

    Missing OVER() clause for LEAD function -> Option B
  4. Quick Check:

    Window functions need OVER() [OK]
Hint: Always use OVER() with LEAD/LAG [OK]
Common Mistakes:
  • Omitting OVER() clause
  • Placing ORDER BY outside OVER()
  • Confusing window functions with aggregates
5. You want to find all employees whose salary increased compared to the previous employee ordered by hire_date. Which query correctly uses LAG to achieve this?
hard
A. SELECT employee_id, salary FROM (SELECT employee_id, salary, LAG(salary) OVER (ORDER BY hire_date) AS prev_salary FROM employees) t WHERE salary > prev_salary;
B. SELECT employee_id, salary FROM employees WHERE salary > (SELECT LAG(salary) FROM employees ORDER BY hire_date);
C. SELECT employee_id, salary, LAG(salary) OVER (ORDER BY hire_date) AS prev_salary FROM employees WHERE salary > prev_salary;
D. SELECT employee_id, salary, LAG(salary) OVER (ORDER BY hire_date) AS prev_salary FROM employees HAVING salary > prev_salary;

Solution

  1. Step 1: Understand LAG usage for filtering

    Window functions like LAG cannot be used directly in WHERE clause; use subquery or CTE to compute then filter.
  2. Step 2: Analyze options

    SELECT employee_id, salary FROM (SELECT employee_id, salary, LAG(salary) OVER (ORDER BY hire_date) AS prev_salary FROM employees) t WHERE salary > prev_salary; correctly uses subquery. The second option's subquery LAG lacks OVER clause (syntax error). The third uses alias in WHERE (invalid). The fourth uses HAVING without GROUP BY (invalid).
  3. Final Answer:

    SELECT employee_id, salary FROM (SELECT employee_id, salary, LAG(salary) OVER (ORDER BY hire_date) AS prev_salary FROM employees) t WHERE salary > prev_salary; -> Option A
  4. Quick Check:

    Subquery to filter on window functions [OK]
Hint: Use subquery to filter on window function results [OK]
Common Mistakes:
  • Using alias in WHERE clause
  • Misusing HAVING without GROUP BY
  • Incorrect subquery for LAG
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard