Code Lab is in development. New lessons and improvements are on the way. Progress can be deleted.
Loading…
Code Lab is in development. New lessons and improvements are on the way. Progress can be deleted.
Loading…
Code Lab is in development. New lessons and improvements are on the way. Progress can be deleted.
SQL / POSTGRESQL / Learn / LESSON 10
A frame tells which rows of the window count for the current row. The explicit form ROWS BETWEEN 2 PRECEDING AND CURRENT ROW means the current row and the two before it. So AVG(total) OVER (ORDER BY order_date, id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) is a moving average of the last 3 ROWS.
ROWS counts rows, not calendar days. If a day has no orders the frame does not "know" about it; it simply takes the previous rows. A true "last 3 days" needs other techniques that we do not cover here. At the start the frame is incomplete — the first row has only itself, the second only two rows. That is normal; COUNT(*) OVER (...) with the same frame shows how many rows really took part.
Other bounds: UNBOUNDED PRECEDING (from the start), n FOLLOWING (forward), CURRENT ROW. Always use a unique tie-breaker in the ORDER BY of OVER and a final ORDER BY.
Common mistakes: reading ROWS as calendar days; a missing tie-breaker; expecting a full frame on the first rows; forgetting rounding.
Small example:
SELECT id, total, SUM(total) OVER (ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS last_two FROM orders ORDER BY id;
Working tables for this task. Grading also uses other datasets with the same schema.
| id | name | category | price |
|---|---|---|---|
| 1 | Atlas | books | 30 |
| 2 | Novel | books | 15 |
| 3 | Comic | books | 14.99 |
| 4 | Lamp | home | 29.99 |
| 5 | Vase | home | 30 |
| 6 | Rug | home | 45 |
| 7 | Hammer | tools | 15 |
| 8 | Drill | tools | 60 |
| 9 | Tape | tools | 15 |
| 10 | Candle | NULL | 8.5 |
| 11 | Gift Card | NULL | 25 |
| id | name | city |
|---|---|---|
| 1 | Mira | Sofia |
| 2 | Niko | Varna |
| 3 | Iva | Sofia |
| 4 | Alex | NULL |
| 5 | Boris | Plovdiv |
| 6 | Lena | Varna |
| 7 | Petya | Sofia |
| id | customer_id | total | order_date |
|---|---|---|---|
| 1 | 1 | 120 | 2024-01-05 |
| 2 | 1 | 35.5 | 2024-01-20 |
| 3 | 2 | 40 | 2024-01-20 |
| 4 | 3 | 99.99 | 2024-01-31 |
| 5 | NULL | 60 | 2024-02-01 |
| 6 | 1 | 40 | 2024-02-01 |
| 7 | 2 | 75.25 | 2024-02-14 |
| 8 | 3 | 100 | 2024-02-15 |
| 9 | 5 | 22 | 2024-02-15 |
| 10 | 1 | 39.99 | 2024-02-29 |
| 11 | 2 | 55 | 2024-03-01 |
| 12 | 3 | 18 | 2024-03-10 |
| 13 | 1 | 130 | 2024-03-15 |
| 14 | 2 | 40 | 2024-03-15 |
| 15 | 2 | 12.5 | 2024-03-31 |
| 16 | 3 | 47 | 2024-04-01 |
Expected columns: id, order_date, total, moving_avg_3 · row order is checked
Expected result (displayed data):
Loading…A frame tells which rows of the window count for the current row. The explicit form ROWS BETWEEN 2 PRECEDING AND CURRENT ROW means the current row and the two before it. So AVG(total) OVER (ORDER BY order_date, id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) is a moving average of the last 3 ROWS. ROWS counts rows, not calendar days. If a day has no orders the frame does not "know" about it; it simply takes the previous rows. A true "last 3 days" needs other techniques that we do not cover here. At the start the frame is incomplete — the first row has only itself, the second only two rows. That is normal; COUNT(*) OVER (...) with the same frame shows how many rows really took part. Other bounds: UNBOUNDED PRECEDING (from the start), n FOLLOWING (forward), CURRENT ROW. Always use a unique tie-breaker in the ORDER BY of OVER and a final ORDER BY. Common mistakes: reading ROWS as calendar days; a missing tie-breaker; expecting a full frame on the first rows; forgetting rounding.
QUERY STANDBY
›