Lessons › SQL › Deep Dive: Advanced Window Functions
SQL lesson
FIRST_VALUE() / LAST_VALUE() / NTH_VALUE()
These window functions (meaning they look across a set of related rows without collapsing them into one) let you reach into a ranked list and pull the value at a specific position - first, last, or anywhere in between - and stamp it alongside every row. Like bookmarking the opening chapter, the final page, and chapter two of every reader's history so you can compare them all at a glance.
Try this lesson free →Example
Navigating Customer Order Values with FIRST_VALUE(), LAST_VALUE(), and NTH_VALUE()
SELECT order_id, customer_id, order_date, revenue, FIRST_VALUE(revenue) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS first_order_revenue, LAST_VALUE(revenue) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_order_revenue, NTH_VALUE(revenue, 2) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS second_order_revenue FROM orders ORDER BY customer_id, order_date| order_id | customer_id | revenue | first_order_revenue | last_order_revenue | second_order_revenue |
|---|---|---|---|---|---|
| O2001 | C101 | 320.0 | 320.0 | 540.0 | 85.5 |
| O2002 | C101 | 85.5 | 320.0 | 540.0 | 85.5 |
| O2003 | C101 | 540.0 | 320.0 | 540.0 | 85.5 |
| O2004 | C102 | 45.0 | 45.0 | 130.75 | 130.75 |
| O2005 | C102 | 130.75 | 45.0 | 130.75 | 130.75 |
Step by step
- AS gives a column a friendlier name in the result.
SELECT order_id, customer_id, order_date, revenue, FIRST_VALUE(revenue) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS first_order_revenue, LAST_VALUE(revenue) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_order_revenue, NTH_VALUE(revenue, 2) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS second_order_revenue - FROM tells SQL which table to pull the data from.
SELECT order_id, customer_id, order_date, revenue, FIRST_VALUE(revenue) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS first_order_revenue, LAST_VALUE(revenue) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_order_revenue, NTH_VALUE(revenue, 2) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS second_order_revenue FROM orders - ORDER BY puts the rows in your chosen order.
SELECT order_id, customer_id, order_date, revenue, FIRST_VALUE(revenue) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS first_order_revenue, LAST_VALUE(revenue) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_order_revenue, NTH_VALUE(revenue, 2) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS second_order_revenue FROM orders ORDER BY customer_id, order_date;
Practice
1. Using orders, write a query that returns the first revenue value within each category group, ordered by revenue.
SELECT *, FIRST_VALUE(revenue) OVER (PARTITION BY category ORDER BY revenue) FROM orders2. Using store_sales, write a query that returns the last revenue value within each sale_id group, ordered by revenue.
SELECT *, LAST_VALUE(revenue) OVER (PARTITION BY sale_id ORDER BY revenue) FROM store_sales3. Using products, write a query that returns the 3nd/3rd price value within each category group, ordered by price.
SELECT *, NTH_VALUE(price, 3) OVER (PARTITION BY category ORDER BY price) FROM products4. Using employees, write a query that returns the first salary value within each full_name group, ordered by salary.
SELECT *, FIRST_VALUE(salary) OVER (PARTITION BY full_name ORDER BY salary) FROM employees5. Using reviews, write a query that returns the last rating value within each review_id group, ordered by rating.
SELECT *, LAST_VALUE(rating) OVER (PARTITION BY review_id ORDER BY rating) FROM reviewsLearn it by doing. This lesson is a short hands-on level on Bampaa: see it work, then build and write it yourself, with instant feedback.
Try this lesson free →