
Window Functions
Window Functions
Activity Solutions


OVER clause.SUM() or AVG(). The OVER() clause defines how rows are organized for the calculation.
GROUP BY for window functions, but it doesn’t hide the individual rows.Using film, return film_id, title, rating, and length for every film with a nonmissing length. Add rating_avg_length: the average length of films with the same rating.
ROW_NUMBER(): Assigns a unique, sequential integer to rows (1, 2, 3, 4).RANK(): Assigns the same rank to ties, but skips the next number (1, 2, 2, 4).DENSE_RANK(): Assigns the same rank to ties, but does not skip numbers (1, 2, 2, 3).
Using films with nonmissing lengths, rank films within each rating, longest film length first. Return film_id, title, rating, film length, and all three rankings:
ROW_NUMBER(): rank by film length and film_id.RANK(): rank by film lengthDENSE_RANK(): rank by film lengthWhat does each ranking do?
LAG(column): Accesses data from the previous row.LEAD(column): Accesses data from the following row.Using payment, examine all payments for customer_id = 1, ordered by payment_date, then payment_id.
payment_id, payment_date, and amount.previous_amount from the preceding payment.Using rental, examine every rental for customers 1, 2, and 3.
customer_id, rental_id, and rental_date.next_rental_date for the same customer, ordered by rental_date, then rental_id.days_until_next, rounded to two decimals.customer_id, rental_date, then rental_id.Hint: In SQLite, JULIANDAY(later) - JULIANDAY(earlier) gives elapsed days, including fractions.
Sometimes, you don’t want to look at the entire partition. You only want a subset of it.
ROWS BETWEEN ...UNBOUNDED PRECEDING: Start from the very first row of the partition.CURRENT ROW: End at the row you are on.1 PRECEDING: Look at exactly one row before.Example: 3-Day Moving Average
Using payment, first create a CTE containing one row per payment date: payment_day and daily_revenue. Use DATE(payment_date) to remove the time.
running_revenue: revenue from the first observed date through the current row.moving_avg_3_rows: average daily revenue over the current row and up to two preceding rows.Window Functions
Activity Solutions
Interpretation: A positive difference means the film is longer than its rating’s average. Unlike GROUP BY, this window calculation retains each film row.
SELECT film_id, title, rating, length,
ROW_NUMBER() OVER (
PARTITION BY rating
ORDER BY length DESC, film_id) AS row_num,
RANK() OVER (
PARTITION BY rating
ORDER BY length DESC) AS length_rank,
DENSE_RANK() OVER (
PARTITION BY rating
ORDER BY length DESC) AS dense_length_rank
FROM film
WHERE length IS NOT NULL
ORDER BY rating, length DESC, film_id;customer_id and orders by payment_date and payment_id.
LEAD() to retrieve the following row’s rental date within the window.
rental_id to break ties when timestamps match. This controls the window calculation, not the final display order.
next_rental_date. Each customer’s final rental returns NULL because no following rental exists.
rental table.
WITH daily_sales AS (
SELECT DATE(payment_date) AS payment_day,
SUM(amount) AS daily_revenue
FROM payment
GROUP BY DATE(payment_date)
)
SELECT payment_day, daily_revenue,
SUM(daily_revenue) OVER (
ORDER BY payment_day
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS running_revenue,
AVG(daily_revenue) OVER (
ORDER BY payment_day
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS moving_avg_3_rows
FROM daily_sales
ORDER BY payment_day;daily_sales to summarize payments before applying window functions.
payment_day.
SUM(amount) calculates total revenue for each date, producing one row per observed payment date.
SUM() over this frame calculates cumulative revenue as running_revenue.
AVG() calculates their average daily revenue. The first result uses one row, the second uses two, and subsequent results use three. These are observed payment dates, not necessarily consecutive calendar days.
OVER() controls calculations but does not guarantee the final display order.