FIRST_VALUE and LAST_VALUE in SQL - Time & Space Complexity
We want to understand how the time it takes to run queries using FIRST_VALUE and LAST_VALUE changes as the data grows.
How does the size of the data affect the work done by these functions?
Analyze the time complexity of the following SQL query using window functions.
SELECT employee_id, department_id, salary,
FIRST_VALUE(salary) OVER (PARTITION BY department_id ORDER BY salary DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS highest_salary,
LAST_VALUE(salary) OVER (PARTITION BY department_id ORDER BY salary DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS lowest_salary
FROM employees;
This query finds the highest and lowest salary in each department for every employee row.
Look for repeated work inside the query.
- Primary operation: Scanning each row and computing window functions per partition.
- How many times: Once per row, but window functions look at all rows in the same department.
As the number of employees grows, the work to find first and last values per department grows too.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 rows scanned, small partitions checked |
| 100 | About 100 rows scanned, partitions larger, more rows checked per partition |
| 1000 | About 1000 rows scanned, partitions much larger, more comparisons per row |
Pattern observation: The work grows roughly in proportion to the number of rows because each row's window looks at its partition.
Time Complexity: O(n)
This means the time to run the query grows roughly in direct proportion to the number of rows.
[X] Wrong: "FIRST_VALUE and LAST_VALUE only look at one row, so they run instantly regardless of data size."
[OK] Correct: These functions scan all rows in each partition to find the first or last value, so bigger partitions mean more work.
Understanding how window functions scale helps you explain query performance clearly and shows you know how databases handle grouped data.
What if we removed the PARTITION BY clause? How would the time complexity change?
Practice
FIRST_VALUE(column_name) OVER (ORDER BY column_name) return?Solution
Step 1: Understand FIRST_VALUE function
It returns the first value in the ordered set of rows defined by the OVER clause.Step 2: Analyze the ORDER BY clause
The ORDER BY inside OVER() defines the order to pick the first value from.Final Answer:
The first value in the ordered set of rows for that column -> Option BQuick Check:
FIRST_VALUE returns first row value [OK]
- Confusing FIRST_VALUE with LAST_VALUE
- Thinking it returns an aggregate like average
- Ignoring the ORDER BY inside OVER()
salary ordered by hire_date in SQL?Solution
Step 1: Understand LAST_VALUE default frame
LAST_VALUE by default looks only at rows up to current row, so it may not return the true last value.Step 2: Use frame clause to include all rows
AddingROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWINGensures LAST_VALUE looks at the entire partition.Final Answer:
SELECT LAST_VALUE(salary) OVER (ORDER BY hire_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) FROM employees; -> Option DQuick Check:
LAST_VALUE needs full frame to get last row [OK]
- Omitting frame clause with LAST_VALUE
- Using PARTITION BY incorrectly
- Trying to use LAST_VALUE without OVER()
sales with columns region and amount, what will this query return?SELECT region, amount, FIRST_VALUE(amount) OVER (PARTITION BY region ORDER BY amount DESC) AS max_amount FROM sales;
Solution
Step 1: Analyze PARTITION BY and ORDER BY
The window partitions rows by region and orders amounts descending within each region.Step 2: Understand FIRST_VALUE with ordering
FIRST_VALUE picks the first row's amount in each partition ordered by amount DESC, which is the max amount.Final Answer:
The highest amount per region repeated on each row of that region -> Option CQuick Check:
FIRST_VALUE with DESC order gives max per partition [OK]
- Assuming FIRST_VALUE always returns lowest value
- Confusing PARTITION BY with filtering
- Expecting syntax error without frame clause here
SELECT employee_id, LAST_VALUE(salary) OVER (ORDER BY employee_id) AS last_sal FROM employees;
Solution
Step 1: Check LAST_VALUE default behavior
By default, LAST_VALUE looks only up to current row, so it may not return the true last value.Step 2: Add frame clause to fix
AddingROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWINGmakes LAST_VALUE consider all rows.Final Answer:
LAST_VALUE needs a frame clause to get correct last value -> Option AQuick Check:
LAST_VALUE without frame returns wrong last row [OK]
- Thinking PARTITION BY is mandatory
- Believing ORDER BY is invalid inside OVER()
- Confusing LAST_VALUE with aggregate functions
sales table. Which query correctly returns both values on each row?Solution
Step 1: Use PARTITION BY customer_id
This groups rows by customer to get first and last sales per customer.Step 2: Use ORDER BY sale_date for chronological order
Ordering by sale_date ensures first and last are by date.Step 3: Add frame clause for LAST_VALUE
LAST_VALUE needsROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWINGto get true last value.Final Answer:
Query in option A correctly returns first and last sale amounts per customer -> Option AQuick Check:
FIRST_VALUE and LAST_VALUE with proper frame and partition [OK]
- Omitting frame clause for LAST_VALUE
- Using aggregate functions instead of window functions
- Not partitioning by customer_id
Ready to prove it?
Pass the test and this pattern moves unknown
