Hook: Interviewers love FIRST_VALUE because it looks simple, but it quietly checks whether you understand ordering, partitions, and determinism.
Question: What does FIRST_VALUE do in SQL?
Answer: FIRST_VALUE is a window function that returns the value from the first row in an ordered window. You usually pair it with PARTITION BY to restart the calculation for each group and ORDER BY to define what “first” means. A key detail is that if two rows tie on the sort key, you should add a tie-breaker so the result is stable.
Interview-Ready Answer: I’d say FIRST_VALUE returns the value from the first row in a window, so it’s great when I want a per-group baseline like the top salary or first event. I usually use PARTITION BY for grouping and ORDER BY to define which row is first, and I add a tie-breaker so the result does not depend on engine row order.
FIRST_VALUE is a window function, meaning it calculates a result across a set of related rows while still returning one output row for each input row. Think of it like a “leader” label: every row in the window can see which row comes first after sorting.
PARTITION BY group, or one big partition if you omit it.ORDER BY list. This is the most important part, because “first” only exists after sorting.FIRST_VALUE(expr) reads expr from the first row in that frame.For many interview questions, the mental model is: partition first, sort second, read the first row third.
| Tool | Meaning | Best use | Main trap |
|---|---|---|---|
FIRST_VALUE | First value by order | Baseline row data | Needs stable ordering |
MIN | Smallest value | Lowest number/date | Ignores row order intent |
ROW_NUMBER + join | Pick row 1, then read columns | Need whole row | More verbose and harder to read |
The sort usually dominates the cost. A good mental estimate is O(n log n) time because the rows must be ordered, with extra memory for sorting. The function itself is cheap after the sort, but large partitions can spill to disk if the engine does not have enough memory. In PostgreSQL-style systems, that can happen when sort memory is only a few MB and the partition is large or wide.
ORDER BY: the result is not meaningful for business logic because “first” has no clear definition.FIRST_VALUE returns the first row’s value even if it is NULL; it does not automatically mean “first non-null.”Rule of thumb: if you can explain which row is first in one sentence, FIRST_VALUE is the right tool.
Imagine an e-commerce checkout service that tracks the first marketing channel for each customer. The analytics team uses FIRST_VALUE(channel) OVER (PARTITION BY customer_id ORDER BY event_time) to label each customer with the channel that brought them in.
One day, the team notices the dashboard keeps shifting: “organic” is 4% higher in the morning, then “ads” wins after the nightly batch. The bug turns out to be ties in event_time. Two events arrive with the same timestamp, and without a tie-breaker like event_id, the engine is free to choose either row first.
What goes wrong: reports become unstable, finance questions attribution numbers, and support sees tickets about “changing totals.” Logs show the same customer row getting a different first channel after reloads or reprocessing. The fix is simple: make the ordering deterministic and, if needed, add a second sort key or pre-clean the data.
-- FIRST_VALUE example in PostgreSQL-compatible SQL.
-- This shows:
-- 1) partitioning by department,
-- 2) ordering to define what "first" means,
-- 3) a tie-breaker for deterministic results,
-- 4) a NULL-safe sort so missing salaries do not accidentally win.
WITH employee_sales AS (
SELECT *
FROM (VALUES
(1, 'Sales', 'Ava', 90000),
(2, 'Sales', 'Ben', 120000),
(3, 'Sales', 'Cara', 120000),
(4, 'Sales', 'Drew', NULL),
(5, 'Engineering', 'Eli', 150000),
(6, 'Engineering', 'Fay', 180000),
(7, 'Engineering', 'Gus', 180000)
) AS v(emp_id, dept, emp_name, salary)
)
SELECT
emp_id,
dept,
emp_name,
salary,
FIRST_VALUE(emp_name) OVER (
PARTITION BY dept
ORDER BY COALESCE(salary, -1) DESC, emp_id
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS top_earner_name,
FIRST_VALUE(salary) OVER (
PARTITION BY dept
ORDER BY COALESCE(salary, -1) DESC, emp_id
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS top_earner_salary
FROM employee_sales
ORDER BY dept, emp_id;
-- Expected behavior:
-- Engineering: Fay is first because 180000 is highest, and emp_id breaks the tie with Gus.
-- Sales: Ben is first because 120000 is highest, and Ben wins the tie against Cara.
-- Drew's NULL salary is pushed to the end so it cannot accidentally become the first row.
-- If you remove emp_id from the ORDER BY, the tied rows can flip between runs in some engines.Follow-up & Tricky Questions:
FIRST_VALUE and MIN? FIRST_VALUE follows the row order you define, while MIN returns the smallest value regardless of row order. If you want the value from the earliest or highest-ranked row, use FIRST_VALUE; if you only want the smallest scalar, use MIN.PARTITION BY change the result? It splits the data into independent groups, so the first value is calculated separately for each group. Without it, the whole result set is treated as one partition.FIRST_VALUE, it usually matches the intended behavior of showing the first row for the entire partition.FIRST_VALUE? It returns the value from the first ordered row even if that value is NULL. If you need the first non-null value, you must use a different pattern or a database-specific feature.ORDER BY? No. If multiple rows tie, the engine may choose any peer row first unless you add a tie-breaker.FIRST_VALUE return the first row in the table? No, it returns the first row in the window order you define. Table storage order is not the same as logical SQL order.FIRST_VALUE the same as “first non-null value”? No. It is about the first sorted row, not about skipping nulls. Many candidates miss this distinction.Common Mistakes:
ORDER BY: fix it by defining a real business order, such as timestamp, score, or amount.id or created_at, id.MIN: fix it by remembering that FIRST_VALUE is order-based, not value-based.Memory Hook: “Partition, sort, spotlight.” First split the group, then sort it, then shine the spotlight on the first row.
Cheat Sheet:
FIRST_VALUE is a window function, not an aggregate.PARTITION BY defines the group.ORDER BY defines what “first” means.Practice Tasks:
MIN incorrectly and replace it with FIRST_VALUE plus a deterministic order.