Skip to content

Commit 6abd3bb

Browse files
feat: added more intermediate exercises (#40)
1 parent 9e2167d commit 6abd3bb

1 file changed

Lines changed: 264 additions & 0 deletions

File tree

exercises/intermediate-exercises.md

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,4 +744,268 @@ HAVING COUNT(DISTINCT DATE_TRUNC('month', order_date)) >= 10;
744744
* `HAVING` filters only customers active in 10+ months.
745745
* Useful for VIP programs or retention campaigns.
746746

747+
---
748+
749+
## 31. Scenario: Employee Hierarchy with Recursion
750+
751+
**Context:**
752+
The HR department wants to list all employees under a particular manager, including indirect reports. The employees table contains `employee_id`, `name`, and `manager_id`.
753+
754+
**Question:**
755+
Write a query to find all employees reporting (directly or indirectly) to manager_id = 1.
756+
757+
**Answer:**
758+
```
759+
WITH RECURSIVE subordinates AS (
760+
SELECT employee_id, name, manager_id
761+
FROM employees
762+
WHERE manager_id = 1
763+
UNION ALL
764+
SELECT e.employee_id, e.name, e.manager_id
765+
FROM employees e
766+
INNER JOIN subordinates s ON e.manager_id = s.employee_id
767+
)
768+
SELECT * FROM subordinates;
769+
```
770+
771+
**Explanation:**
772+
* Recursive CTE subordinates finds direct reports first.
773+
* UNION ALL recursively adds indirect reports.
774+
* Useful for building organizational hierarchies.
775+
776+
---
777+
778+
## 32. Scenario: Top 3 Products per Category
779+
780+
**Context:**
781+
Marketing wants to know the top-selling products in each category. The orders table contains product_id, quantity, and price. The products table contains product_id and category.
782+
783+
**Question:**
784+
Write a query to find the top 3 products by revenue in each category.
785+
**Answer:**
786+
```
787+
SELECT category, product_id, total_revenue
788+
FROM (
789+
SELECT p.category, o.product_id, SUM(o.quantity * o.price) AS total_revenue,
790+
RANK() OVER (PARTITION BY p.category ORDER BY SUM(o.quantity * o.price) DESC) AS rnk
791+
FROM orders o
792+
JOIN products p ON o.product_id = p.product_id
793+
GROUP BY p.category, o.product_id
794+
) t
795+
WHERE rnk <= 3;
796+
797+
```
798+
799+
**Explanation:**
800+
* Uses window function RANK() partitioned by category.
801+
* Aggregates revenue per product.
802+
* Filters top 3 per category with WHERE rnk <= 3.
803+
804+
---
805+
806+
## 33. Scenario: JSONB Nested Filtering
807+
808+
**Context:**
809+
The user table stores preferences in a JSONB column preferences. Each JSON object contains keys like "notifications": {"email": true, "sms": false}.
810+
811+
**Question:**
812+
Write a query to find all users who have email notifications enabled.
813+
814+
**Answer:**
815+
```
816+
SELECT user_id, preferences
817+
FROM users
818+
WHERE preferences -> 'notifications' ->> 'email' = 'true';
819+
820+
```
821+
822+
**Explanation:**
823+
* Navigates nested JSONB with -> and ->>.
824+
* Filters only users with email notifications enabled.
825+
826+
---
827+
828+
## 34. Scenario: Lateral Join for Latest Order per Customer
829+
830+
**Context:**
831+
The sales team wants each customer’s latest order. The customers table has customer_id. The orders table has order_id, customer_id, and order_date.
832+
833+
834+
**Question:**
835+
Write a query to retrieve each customer and their most recent order
836+
837+
**Answer:**
838+
```
839+
SELECT c.customer_id, o.order_id, o.order_date
840+
FROM customers c
841+
LEFT JOIN LATERAL (
842+
SELECT order_id, order_date
843+
FROM orders
844+
WHERE customer_id = c.customer_id
845+
ORDER BY order_date DESC
846+
LIMIT 1
847+
) o ON true;
848+
849+
```
850+
851+
**Explanation:**
852+
* LATERAL allows referencing the outer query row.
853+
* Retrieves the latest order per customer efficiently.
747854

855+
---
856+
857+
## 35. Scenario: Full-Text Search with Ranking
858+
859+
**Context:**
860+
A blog wants to rank articles by relevance to the term "PostgreSQL optimization". The articles table has title and content.
861+
862+
**Question:**
863+
Write a query to rank articles using full-text search.
864+
865+
**Answer:**
866+
```
867+
SELECT title, ts_rank_cd(to_tsvector(content), to_tsquery('PostgreSQL & optimization')) AS rank
868+
FROM articles
869+
WHERE to_tsvector(content) @@ to_tsquery('PostgreSQL & optimization')
870+
ORDER BY rank DESC;
871+
872+
```
873+
874+
**Explanation:**
875+
* ts_rank_cd ranks matches by relevance.
876+
* @@ filters only relevant rows.
877+
* Useful for search results sorted by importance.
878+
879+
---
880+
881+
## 36. Scenario: Materialized View for Monthly Sales
882+
883+
**Context:**
884+
Finance wants a precomputed table of monthly sales totals for faster reporting. Orders table has order_date and total_amount.
885+
886+
**Question:**
887+
Write commands to create a materialized view and refresh it.
888+
889+
**Answer:**
890+
```
891+
CREATE MATERIALIZED VIEW monthly_sales AS
892+
SELECT DATE_TRUNC('month', order_date) AS month, SUM(total_amount) AS total_sales
893+
FROM orders
894+
GROUP BY month;
895+
896+
-- Refresh when data changes
897+
REFRESH MATERIALIZED VIEW monthly_sales;
898+
899+
```
900+
901+
**Explanation:**
902+
* Materialized view stores query results physically.
903+
* Refresh updates data periodically.
904+
* Speeds up repeated heavy queries.
905+
906+
---
907+
908+
## 37. Scenario: Transaction Isolation Test
909+
910+
**Context:**
911+
The bank wants to test how SERIALIZABLE isolation prevents lost updates. The accounts table has account_id and balance.
912+
913+
**Question:**
914+
Demonstrate a transaction that safely increments an account balance by 100.
915+
916+
**Answer:**
917+
```
918+
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
919+
920+
UPDATE accounts
921+
SET balance = balance + 100
922+
WHERE account_id = 1;
923+
924+
COMMIT;
925+
926+
```
927+
928+
**Explanation:**
929+
* SERIALIZABLE prevents conflicts with concurrent transactions.
930+
* Ensures consistency in highly concurrent environments.
931+
932+
---
933+
934+
## 38. Scenario: Partitioned Table Query
935+
936+
**Context:**
937+
A log system stores millions of rows in a logs table partitioned by month. Each partition is named logs_YYYY_MM.
938+
939+
**Question:**
940+
Write a query to retrieve all logs from October 2025.
941+
942+
**Answer:**
943+
```
944+
SELECT *
945+
FROM logs
946+
WHERE log_date >= '2025-10-01' AND log_date < '2025-11-01';
947+
948+
```
949+
950+
**Explanation:**
951+
* Partitioning ensures query only scans relevant data.
952+
* Improves performance on large tables.
953+
954+
---
955+
956+
## 39. Scenario: Array Aggregation
957+
958+
**Context:**
959+
Marketing wants a list of all products each customer purchased. Orders table has customer_id and product_id.
960+
961+
**Question:**
962+
Write a query to return each customer with an array of product_ids
963+
964+
**Answer:**
965+
```
966+
SELECT customer_id, ARRAY_AGG(product_id) AS products
967+
FROM orders
968+
GROUP BY customer_id;
969+
970+
```
971+
972+
**Explanation:**
973+
* ARRAY_AGG aggregates multiple rows into an array per group.
974+
* Useful for reporting or exporting data in structured form.
975+
976+
---
977+
978+
## 40. Scenario: Combined Advanced Query
979+
980+
**Context:**
981+
A platform wants VIP customers (spent > $10k last year) and their top 3 most purchased products. Orders table has customer_id, product_id, and total_amount.
982+
983+
**Question:**
984+
Write a query combining aggregation, ranking, and filtering.
985+
986+
**Answer:**
987+
```
988+
WITH vip AS (
989+
SELECT customer_id
990+
FROM orders
991+
WHERE order_date >= CURRENT_DATE - INTERVAL '1 year'
992+
GROUP BY customer_id
993+
HAVING SUM(total_amount) > 10000
994+
),
995+
product_ranks AS (
996+
SELECT customer_id, product_id, COUNT(*) AS qty,
997+
RANK() OVER (PARTITION BY customer_id ORDER BY COUNT(*) DESC) AS rnk
998+
FROM orders
999+
WHERE customer_id IN (SELECT customer_id FROM vip)
1000+
GROUP BY customer_id, product_id
1001+
)
1002+
SELECT customer_id, product_id, qty
1003+
FROM product_ranks
1004+
WHERE rnk <= 3;
1005+
1006+
```
1007+
1008+
**Explanation:**
1009+
* CTE vip filters high-value customers.
1010+
* Window function ranks products per customer.
1011+
* Combines multiple advanced features in a single query.

0 commit comments

Comments
 (0)