Skip to content

Comprehensive Exercises

Tables

products — Products (name, price, stock, brand)

customers — Customers (grade, points, channel)

orders — Orders (status, amount, date)

reviews — Reviews (rating, content)

payments — Payments (method, amount, status)

categories — Categories (parent-child hierarchy)

suppliers — Suppliers (company, contact)

Concepts

SELECT, WHERE, ORDER BY, LIMIT, Aggregate functions, GROUP BY, HAVING, IS NULL, COALESCE, CASE

1. Query the name, brand, and price of the top 5 most expensive

Query the name, brand, and price of the top 5 most expensive active products (is_active = 1).

Hint 1: This is a combination of WHERE filtering + ORDER BY DESC + LIMIT.

Answer
SELECT name, brand, price
FROM products
WHERE is_active = 1
ORDER BY price DESC
LIMIT 5;

Result (5 rows)

name brand price
MacBook Air 15 M3 Silver Apple 5,481,100.00
ASUS Dual RTX 5070 Ti [Special Limite... ASUS 4,496,700.00
Razer Blade 18 Black Razer 4,353,100.00
Razer Blade 16 Silver Razer 3,702,900.00
ASUS ROG Strix G16CH White ASUS 3,671,500.00

2. Query the name and last login date of VIP-tier customers who

Query the name and last login date of VIP-tier customers who have a login history, sorted by most recent, limited to 10 rows.

Hint 1: Combine two conditions with WHERE grade = 'VIP' AND last_login_at IS NOT NULL.

Answer
SELECT name, last_login_at
FROM customers
WHERE grade = 'VIP'
  AND last_login_at IS NOT NULL
ORDER BY last_login_at DESC
LIMIT 10;

Result (top 7 of 10 rows)

name last_login_at
Leslie Mccoy 2025-12-30 20:20:12
Christopher Morris 2025-12-30 17:25:30
Angela Clements 2025-12-30 17:24:28
Jordan Pearson 2025-12-30 12:28:17
Mr. James Bean 2025-12-30 02:06:50
Lindsay Douglas 2025-12-30 00:15:41
Sandra Williams 2025-12-29 21:08:21

3. Query the order number, order amount, and cancellation date

Query the order number, order amount, and cancellation date of cancelled orders in 2024, sorted by most recent cancellation, limited to 10 rows.

Hint 1: Combine conditions with WHERE ordered_at LIKE '2024%' AND cancelled_at IS NOT NULL.

Answer
SELECT order_number, total_amount, cancelled_at
FROM orders
WHERE ordered_at LIKE '2024%'
  AND cancelled_at IS NOT NULL
ORDER BY cancelled_at DESC
LIMIT 10;

Result (top 7 of 10 rows)

order_number total_amount cancelled_at
ORD-20241231-31231 1,905,400.00 2025-01-01 23:25:27
ORD-20241229-31194 657,900.00 2024-12-31 11:37:44
ORD-20241228-31179 68,900.00 2024-12-30 00:01:41
ORD-20241228-31177 289,100.00 2024-12-28 21:35:05
ORD-20241226-31148 69,400.00 2024-12-27 20:44:43
ORD-20241225-31134 2,841,800.00 2024-12-26 18:43:50
ORD-20241223-31096 234,768.00 2024-12-25 19:56:46

4. Find the count and average rating of reviews with a rating o

Find the count and average rating of reviews with a rating of 4 or higher. Display the average to 2 decimal places.

Hint 1: Filter with WHERE rating >= 4, then use COUNT(*) and ROUND(AVG(rating), 2).

Answer
SELECT COUNT(*) AS high_rating_count,
       ROUND(AVG(rating), 2) AS avg_rating
FROM reviews
WHERE rating >= 4;

Result (1 rows)

high_rating_count avg_rating
6008 4.57

5. Find the number of active products per brand, showing only b

Find the number of active products per brand, showing only brands with 10 or more, sorted by product count descending.

Hint 1: This is a combination of WHERE is_active = 1 + GROUP BY brand + HAVING COUNT(*) >= 10.

Answer
SELECT brand, COUNT(*) AS product_count
FROM products
WHERE is_active = 1
GROUP BY brand
HAVING COUNT(*) >= 10
ORDER BY product_count DESC;

Result (6 rows)

brand product_count
Samsung 21
ASUS 21
MSI 12
TP-Link 11
Logitech 11
LG 11

6. Find the average points per customer tier, displaying the ti

Find the average points per customer tier, displaying the tier in Korean. Sort by average points descending.

Hint 1: This is a combination of CASE for tier conversion + GROUP BY + AVG + ORDER BY.

Answer
SELECT CASE grade
           WHEN 'VIP' THEN 'VIP'
           WHEN 'GOLD' THEN '골드'
           WHEN 'SILVER' THEN '실버'
           WHEN 'BRONZE' THEN '브론즈'
       END AS grade_kr,
       ROUND(AVG(point_balance)) AS avg_points
FROM customers
GROUP BY grade
ORDER BY avg_points DESC;

Result (4 rows)

grade_kr avg_points
VIP 407,015.00
골드 147,711.00
실버 95,042.00
브론즈 16,779.00

7. Find the total payment amount and count per payment method,

Find the total payment amount and count per payment method, showing only methods with a total of 1 billion or more.

Hint 1: This is a combination of GROUP BY method + HAVING SUM(amount) >= 1000000000.

Answer
SELECT method,
       COUNT(*) AS payment_count,
       ROUND(SUM(amount)) AS total_amount
FROM payments
GROUP BY method
HAVING SUM(amount) >= 1000000000
ORDER BY total_amount DESC;

Result (6 rows)

method payment_count total_amount
card 16,841 17,004,951,634.00
kakao_pay 7486 7,563,829,668.00
naver_pay 5715 5,998,835,720.00
bank_transfer 3718 3,753,149,013.00
point 1921 1,951,369,604.00
virtual_account 1876 1,911,359,424.00

8. Find the count per tier for customers with a NULL signup cha

Find the count per tier for customers with a NULL signup channel. Use CASE to sort tiers in order starting from VIP.

Hint 1: This is a combination of WHERE acquisition_channel IS NULL + GROUP BY grade + ORDER BY CASE.

Answer
SELECT grade, COUNT(*) AS customer_count
FROM customers
WHERE acquisition_channel IS NULL
GROUP BY grade
ORDER BY CASE grade
             WHEN 'VIP' THEN 1
             WHEN 'GOLD' THEN 2
             WHEN 'SILVER' THEN 3
             WHEN 'BRONZE' THEN 4
         END;

9. Find the count, average order amount, and delivery notes com

Find the count, average order amount, and delivery notes completion rate (%) per order status. Sort by count descending.

Hint 1: Calculate the completion rate with COUNT(notes) * 100.0 / COUNT(*). This leverages the relationship between NULL and aggregate functions.

Answer
SELECT status,
       COUNT(*) AS order_count,
       ROUND(AVG(total_amount)) AS avg_amount,
       ROUND(COUNT(notes) * 100.0 / COUNT(*), 1) AS notes_rate_pct
FROM orders
GROUP BY status
ORDER BY order_count DESC;

Result (top 7 of 9 rows)

status order_count avg_amount notes_rate_pct
confirmed 34,393 999,814.00 35.30
cancelled 1859 1,045,258.00 34.30
return_requested 507 1,600,567.00 33.10
returned 493 1,337,616.00 34.90
delivered 125 1,566,146.00 28.80
pending 82 1,063,783.00 37.80
shipped 51 1,452,364.00 31.40

10. Classify products by stock status (Out of stock/Low/Normal/S

Classify products by stock status (Out of stock/Low/Normal/Sufficient) and find the product count and average price per group. Active products only.

Hint 1: This is a combination of WHERE is_active = 1 + CASE for stock classification + GROUP BY + aggregate functions.

Answer
SELECT CASE
           WHEN stock_qty = 0 THEN '품절'
           WHEN stock_qty <= 10 THEN '부족'
           WHEN stock_qty <= 100 THEN '보통'
           ELSE '충분'
       END AS stock_status,
       COUNT(*) AS product_count,
       ROUND(AVG(price)) AS avg_price
FROM products
WHERE is_active = 1
GROUP BY stock_status
ORDER BY product_count DESC;

Result (4 rows)

stock_status product_count avg_price
충분 181 669,318.00
보통 34 662,359.00
부족 2 50,900.00
품절 1 23,000.00

11. Find the active product count, average price, and average ma

Find the active product count, average price, and average margin rate (%) per brand. Show only brands with 5+ products, sorted by average margin rate descending.

Hint 1: Margin rate = (price - cost_price) * 100.0 / price. This is a combination of WHERE + GROUP BY + HAVING + ORDER BY.

Answer
SELECT brand,
       COUNT(*) AS product_count,
       ROUND(AVG(price)) AS avg_price,
       ROUND(AVG((price - cost_price) * 100.0 / price), 1) AS avg_margin_pct
FROM products
WHERE is_active = 1
GROUP BY brand
HAVING COUNT(*) >= 5
ORDER BY avg_margin_pct DESC;

Result (top 7 of 17 rows)

brand product_count avg_price avg_margin_pct
Microsoft 5 129,260.00 38.20
SteelSeries 7 212,643.00 31.60
TP-Link 11 128,764.00 30.30
NZXT 5 213,100.00 29.70
Logitech 11 115,127.00 28.00
ASUS 21 1,589,552.00 28.00
ASRock 9 493,244.00 25.60

12. Find the order count, total revenue, average order amount, a

Find the order count, total revenue, average order amount, and cancellation count per year. The cancellation count is the number of rows where cancelled_at is not NULL.

Hint 1: Extract the year with SUBSTR(ordered_at, 1, 4). COUNT(cancelled_at) counts only non-NULL rows.

Answer
SELECT SUBSTR(ordered_at, 1, 4) AS year,
       COUNT(*) AS order_count,
       ROUND(SUM(total_amount)) AS total_revenue,
       ROUND(AVG(total_amount)) AS avg_amount,
       COUNT(cancelled_at) AS cancelled_count
FROM orders
GROUP BY year
ORDER BY year;

Result (top 7 of 10 rows)

year order_count total_revenue avg_amount cancelled_count
2016 416 331,746,909.00 797,469.00 15
2017 709 653,085,068.00 921,135.00 41
2018 1319 1,249,197,907.00 947,080.00 64
2019 2589 2,620,111,601.00 1,012,017.00 116
2020 4319 4,468,755,264.00 1,034,674.00 191
2021 5841 6,044,718,738.00 1,034,877.00 270
2022 5203 5,302,071,035.00 1,019,041.00 256

13. Find the customer count, VIP rate (%), and average points pe

Find the customer count, VIP rate (%), and average points per signup channel. Display 'Unclassified' for NULL channels, sorted by customer count descending.

Hint 1: This is a combination of COALESCE for NULL replacement + SUM(CASE WHEN grade = 'VIP' THEN 1 ELSE 0 END) for VIP count aggregation + GROUP BY.

Answer
SELECT COALESCE(acquisition_channel, '미분류') AS channel,
       COUNT(*) AS customer_count,
       ROUND(SUM(CASE WHEN grade = 'VIP' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS vip_rate_pct,
       ROUND(AVG(point_balance)) AS avg_points
FROM customers
GROUP BY COALESCE(acquisition_channel, '미분류')
ORDER BY customer_count DESC;

Result (5 rows)

channel customer_count vip_rate_pct avg_points
search_ad 1543 7.50 62,449.00
social 1425 6.20 54,311.00
organic 1146 7.10 76,371.00
referral 708 7.20 66,944.00
direct 408 7.80 70,562.00

14. Find the monthly order count and average order amount for 20

Find the monthly order count and average order amount for 2024, also displaying the season (Spring/Summer/Fall/Winter).

Hint 1: This is a combination of SUBSTR for month extraction + CASE for season classification + GROUP BY + aggregation.

Answer
SELECT SUBSTR(ordered_at, 1, 7) AS month,
       CASE
           WHEN CAST(SUBSTR(ordered_at, 6, 2) AS INTEGER) IN (3, 4, 5) THEN '봄'
           WHEN CAST(SUBSTR(ordered_at, 6, 2) AS INTEGER) IN (6, 7, 8) THEN '여름'
           WHEN CAST(SUBSTR(ordered_at, 6, 2) AS INTEGER) IN (9, 10, 11) THEN '가을'
           ELSE '겨울'
       END AS season,
       COUNT(*) AS order_count,
       ROUND(AVG(total_amount)) AS avg_amount
FROM orders
WHERE ordered_at LIKE '2024%'
GROUP BY month
ORDER BY month;

Result (top 7 of 12 rows)

month season order_count avg_amount
2024-01 겨울 346 925,700.00
2024-02 겨울 465 966,554.00
2024-03 601 948,084.00
2024-04 506 980,283.00
2024-05 415 1,140,347.00
2024-06 여름 415 962,619.00
2024-07 여름 414 926,084.00

15. Aggregate reviews by rating, displaying the Korean label, co

Aggregate reviews by rating, displaying the Korean label, count, overall percentage (%), and title completion rate (%) for each rating. Sort by rating descending.

Hint 1: This is a combination of CASE for rating labels + COUNT(*) + percentage calculation + COUNT(title).

Answer
SELECT rating,
       CASE rating
           WHEN 5 THEN '최고'
           WHEN 4 THEN '좋음'
           WHEN 3 THEN '보통'
           WHEN 2 THEN '별로'
           WHEN 1 THEN '최악'
       END AS rating_label,
       COUNT(*) AS review_count,
       ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 1) AS pct,
       ROUND(COUNT(title) * 100.0 / COUNT(*), 1) AS title_rate_pct
FROM reviews
GROUP BY rating
ORDER BY rating DESC;

Result (5 rows)

rating rating_label review_count pct title_rate_pct
5 최고 3433 40.20 80.80
4 좋음 2575 30.10 80.50
3 보통 1265 14.80 80.10
2 별로 839 9.80 80.30
1 최악 434 5.10 80.60

16. Find the product count, average stock, and discontinuation r

Find the product count, average stock, and discontinuation rate (%) per price tier (Budget/Mid-low/Mid/Premium). The discontinuation rate is the percentage of is_active=0.

Hint 1: This is a combination of CASE for price tier classification + SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END) for discontinuation count + GROUP BY.

Answer
SELECT CASE
           WHEN price < 100000 THEN '저가'
           WHEN price < 500000 THEN '중저가'
           WHEN price < 1000000 THEN '중가'
           ELSE '고가'
       END AS price_tier,
       COUNT(*) AS product_count,
       ROUND(AVG(stock_qty)) AS avg_stock,
       ROUND(SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS discontinued_pct
FROM products
GROUP BY price_tier
ORDER BY product_count DESC;

Result (4 rows)

price_tier product_count avg_stock discontinued_pct
중저가 130 277.00 23.80
고가 65 271.00 20.00
저가 47 267.00 19.10
중가 38 282.00 23.70

17. Query the customer count, average points, gender completion

Query the customer count, average points, gender completion rate (%), and login experience rate (%) per tier in a single query. Tier order: VIP > GOLD > SILVER > BRONZE.

Hint 1: Use COUNT(gender) for gender completion count and COUNT(last_login_at) for login experience count. Use ORDER BY CASE for tier ordering.

Answer
SELECT grade,
       COUNT(*) AS customer_count,
       ROUND(AVG(point_balance)) AS avg_points,
       ROUND(COUNT(gender) * 100.0 / COUNT(*), 1) AS gender_rate_pct,
       ROUND(COUNT(last_login_at) * 100.0 / COUNT(*), 1) AS login_rate_pct
FROM customers
GROUP BY grade
ORDER BY CASE grade
             WHEN 'VIP' THEN 1
             WHEN 'GOLD' THEN 2
             WHEN 'SILVER' THEN 3
             WHEN 'BRONZE' THEN 4
         END;

Result (4 rows)

grade customer_count avg_points gender_rate_pct login_rate_pct
VIP 368 407,015.00 96.20 100.00
GOLD 524 147,711.00 92.20 100.00
SILVER 479 95,042.00 90.60 100.00
BRONZE 3859 16,779.00 88.90 92.70

18. Classify orders into 3 status groups (Processing/Completed/C

Classify orders into 3 status groups (Processing/Completed/Cancelled-Returned) and find the count, total revenue, average shipping fee, and points-used count per group.

Hint 1: Classify groups with CASE WHEN status IN (...). Count points-used orders with SUM(CASE WHEN point_used > 0 THEN 1 ELSE 0 END).

Answer
SELECT CASE
           WHEN status IN ('pending', 'paid', 'preparing') THEN '처리중'
           WHEN status IN ('shipped', 'delivered', 'confirmed') THEN '완료'
           ELSE '취소/반품'
       END AS status_group,
       COUNT(*) AS order_count,
       ROUND(SUM(total_amount)) AS total_revenue,
       ROUND(AVG(shipping_fee)) AS avg_shipping,
       SUM(CASE WHEN point_used > 0 THEN 1 ELSE 0 END) AS point_used_count
FROM orders
GROUP BY status_group
ORDER BY order_count DESC;

Result (3 rows)

status_group order_count total_revenue avg_shipping point_used_count
완료 34,569 34,656,428,960.00 248.00 3439
취소/반품 2859 3,414,067,056.00 208.00 291
처리중 129 112,999,047.00 163.00 10

19. For card payments, find the payment count, average amount, a

For card payments, find the payment count, average amount, and installment usage rate (%) per card issuer. Exclude records where card issuer is NULL, and show only card issuers with 100+ payments.

Hint 1: Filter with WHERE method = 'card' AND card_issuer IS NOT NULL. Count installment payments with SUM(CASE WHEN installment_months > 0 THEN 1 ELSE 0 END).

Answer
SELECT card_issuer,
       COUNT(*) AS payment_count,
       ROUND(AVG(amount)) AS avg_amount,
       ROUND(SUM(CASE WHEN installment_months > 0 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS installment_rate_pct
FROM payments
WHERE method = 'card'
  AND card_issuer IS NOT NULL
GROUP BY card_issuer
HAVING COUNT(*) >= 100
ORDER BY payment_count DESC;

Result (7 rows)

card_issuer payment_count avg_amount installment_rate_pct
Visa 5098 993,811.00 48.50
Mastercard 4039 1,063,479.00 47.90
American Express 2513 1,040,512.00 48.50
Discover 1710 990,777.00 48.60
Capital One 1377 961,365.00 48.50
Chase 1252 991,999.00 47.60
Citi 852 901,753.00 48.00

20. Find the product count and active product rate (%) per suppl

Find the product count and active product rate (%) per supplier. Only include suppliers with 3+ products, sorted by active rate descending. Group by supplier_id.

Hint 1: This is a combination of GROUP BY supplier_id + HAVING COUNT(*) >= 3 + SUM(CASE WHEN is_active = 1 ...) for active rate calculation + ORDER BY.

Answer
SELECT supplier_id,
       COUNT(*) AS product_count,
       SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) AS active_count,
       ROUND(SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS active_rate_pct
FROM products
GROUP BY supplier_id
HAVING COUNT(*) >= 3
ORDER BY active_rate_pct DESC;

Result (top 7 of 32 rows)

supplier_id product_count active_count active_rate_pct
2 11 11 100.00
17 6 6 100.00
22 3 3 100.00
24 5 5 100.00
36 11 11 100.00
37 5 5 100.00
27 13 12 92.30

21. Find the active product count and average price per brand, s

Find the active product count and average price per brand, showing only brands with an average price of 1M+. Also display the price tier classification (Premium/Mainstream/Budget).

Hint 1: This is a combination of WHERE is_active = 1 + GROUP BY brand + HAVING AVG(price) >= 1000000 + CASE for price tier classification.

Answer
SELECT brand,
       COUNT(*) AS active_product_count,
       ROUND(AVG(price)) AS avg_price,
       CASE
           WHEN AVG(price) >= 2000000 THEN '프리미엄'
           WHEN AVG(price) >= 1000000 THEN '대중'
           ELSE '보급형'
       END AS brand_tier
FROM products
WHERE is_active = 1
GROUP BY brand
HAVING AVG(price) >= 1000000
ORDER BY avg_price DESC;

Result (top 7 of 8 rows)

brand active_product_count avg_price brand_tier
Apple 2 2,815,400.00 프리미엄
Razer 7 1,996,443.00 대중
Lenovo 2 1,695,450.00 대중
Jooyon Tech 3 1,614,633.00 대중
ASUS 21 1,589,552.00 대중
BenQ 1 1,476,300.00 대중
HP 5 1,433,140.00 대중

22. 2024 monthly revenue analysis: Find the monthly order count,

2024 monthly revenue analysis: Find the monthly order count, total revenue, average order amount, cancellation rate (%), and free shipping rate (%).

Hint 1: Combine various aggregations. Cancellation rate = COUNT(cancelled_at) / COUNT(*). Free shipping = percentage of orders with shipping_fee = 0.

Answer
SELECT SUBSTR(ordered_at, 1, 7) AS month,
       COUNT(*) AS order_count,
       ROUND(SUM(total_amount)) AS total_revenue,
       ROUND(AVG(total_amount)) AS avg_amount,
       ROUND(COUNT(cancelled_at) * 100.0 / COUNT(*), 1) AS cancel_rate_pct,
       ROUND(SUM(CASE WHEN shipping_fee = 0 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS free_ship_pct
FROM orders
WHERE ordered_at LIKE '2024%'
GROUP BY month
ORDER BY month;

Result (top 7 of 12 rows)

month order_count total_revenue avg_amount cancel_rate_pct free_ship_pct
2024-01 346 320,292,182.00 925,700.00 6.10 91.30
2024-02 465 449,447,834.00 966,554.00 6.90 92.30
2024-03 601 569,798,709.00 948,084.00 4.80 93.30
2024-04 506 496,023,258.00 980,283.00 5.50 94.50
2024-05 415 473,243,857.00 1,140,347.00 4.60 94.00
2024-06 415 399,487,004.00 962,619.00 4.30 93.70
2024-07 414 383,398,728.00 926,084.00 5.60 93.50

23. Customer segment analysis: Combine tier and activity status

Customer segment analysis: Combine tier and activity status (Active/Dormant/Withdrawn) to find the customer count and average points per segment. Show only segments with 100+ customers.

Hint 1: Classify activity status with CASE (is_active=0 is Withdrawn, last_login_at IS NULL is Dormant, the rest is Active). Combine with GROUP BY grade, activity_status.

Answer
SELECT grade,
       CASE
           WHEN is_active = 0 THEN '탈퇴'
           WHEN last_login_at IS NULL THEN '휴면'
           ELSE '활동'
       END AS activity_status,
       COUNT(*) AS customer_count,
       ROUND(AVG(point_balance)) AS avg_points
FROM customers
GROUP BY grade, activity_status
HAVING COUNT(*) >= 100
ORDER BY CASE grade
             WHEN 'VIP' THEN 1
             WHEN 'GOLD' THEN 2
             WHEN 'SILVER' THEN 3
             WHEN 'BRONZE' THEN 4
         END,
         customer_count DESC;

Result (6 rows)

grade activity_status customer_count avg_points
VIP 활동 368 407,015.00
GOLD 활동 524 147,711.00
SILVER 활동 479 95,042.00
BRONZE 활동 2100 30,834.00
BRONZE 탈퇴 1570 0.0
BRONZE 휴면 189 0.0

24. Product data quality report: Find the product count, descrip

Product data quality report: Find the product count, description missing rate (%), specs missing rate (%), and weight missing rate (%) per brand. Only include brands with 10+ products, sorted by the overall missing rate (average of all three) descending.

Hint 1: Calculate each column's missing rate with (COUNT(*) - COUNT(column)) * 100.0 / COUNT(*). Sort by the average of the three missing rates.

Answer
SELECT brand,
       COUNT(*) AS product_count,
       ROUND((COUNT(*) - COUNT(description)) * 100.0 / COUNT(*), 1) AS desc_missing_pct,
       ROUND((COUNT(*) - COUNT(specs)) * 100.0 / COUNT(*), 1) AS specs_missing_pct,
       ROUND((COUNT(*) - COUNT(weight_grams)) * 100.0 / COUNT(*), 1) AS weight_missing_pct
FROM products
GROUP BY brand
HAVING COUNT(*) >= 10
ORDER BY (
    (COUNT(*) - COUNT(description)) +
    (COUNT(*) - COUNT(specs)) +
    (COUNT(*) - COUNT(weight_grams))
) * 1.0 / COUNT(*) DESC;

Result (7 rows)

brand product_count desc_missing_pct specs_missing_pct weight_missing_pct
TP-Link 11 0.0 100.00 0.0
Logitech 17 0.0 100.00 0.0
ASRock 11 0.0 100.00 0.0
MSI 13 0.0 61.50 0.0
ASUS 26 0.0 30.80 0.0
Samsung 25 0.0 24.00 0.0
LG 11 0.0 0.0 0.0

25. Yearly customer signup analysis: Find the customer count, ge

Yearly customer signup analysis: Find the customer count, gender ratio (Male/Female/Unknown), and average points per signup year.

Hint 1: Calculate the male ratio with SUM(CASE WHEN gender = 'M' THEN 1 ELSE 0 END) * 100.0 / COUNT(*). Also calculate the NULL gender ratio separately.

Answer
SELECT SUBSTR(created_at, 1, 4) AS join_year,
       COUNT(*) AS customer_count,
       ROUND(SUM(CASE WHEN gender = 'M' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS male_pct,
       ROUND(SUM(CASE WHEN gender = 'F' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS female_pct,
       ROUND(SUM(CASE WHEN gender IS NULL THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS unknown_pct,
       ROUND(AVG(point_balance)) AS avg_points
FROM customers
GROUP BY join_year
ORDER BY join_year;

Result (top 7 of 10 rows)

join_year customer_count male_pct female_pct unknown_pct avg_points
2016 100 53.00 29.00 18.00 212,578.00
2017 180 57.20 32.20 10.60 170,364.00
2018 300 56.30 32.00 11.70 144,012.00
2019 450 56.90 32.70 10.40 99,968.00
2020 700 61.60 28.70 9.70 94,152.00
2021 800 56.30 33.00 10.80 69,793.00
2022 650 60.60 30.30 9.10 53,009.00

26. Discount analysis: For 2024 orders, combine discount status

Discount analysis: For 2024 orders, combine discount status (Has discount/No discount) and amount tier (Small/Regular/Large/VIP-level) to find the count and average order amount.

Hint 1: Classify discount status with CASE WHEN discount_amount > 0 and amount tier with CASE WHEN total_amount < 50000. Use both CASE expressions in GROUP BY.

Answer
SELECT CASE WHEN discount_amount > 0 THEN '할인있음' ELSE '할인없음' END AS has_discount,
       CASE
           WHEN total_amount < 50000 THEN '소액'
           WHEN total_amount < 200000 THEN '일반'
           WHEN total_amount < 1000000 THEN '고액'
           ELSE 'VIP급'
       END AS amount_tier,
       COUNT(*) AS order_count,
       ROUND(AVG(total_amount)) AS avg_amount
FROM orders
WHERE ordered_at LIKE '2024%'
GROUP BY has_discount, amount_tier
ORDER BY has_discount, avg_amount DESC;

Result (top 7 of 8 rows)

has_discount amount_tier order_count avg_amount
할인없음 VIP급 1314 2,190,896.00
할인없음 고액 1498 447,381.00
할인없음 일반 1435 121,632.00
할인없음 소액 276 36,244.00
할인있음 VIP급 652 2,567,481.00
할인있음 고액 398 481,555.00
할인있음 일반 173 125,703.00

27. Product status by category: Find the total product count, ac

Product status by category: Find the total product count, active count, discontinued count, out-of-stock count, and average price per category_id. Only include categories with 5+ total products.

Hint 1: Use SUM(CASE WHEN condition THEN 1 ELSE 0 END) to aggregate each status count into separate columns.

Answer
SELECT category_id,
       COUNT(*) AS total,
       SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) AS active_count,
       SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END) AS discontinued_count,
       SUM(CASE WHEN stock_qty = 0 THEN 1 ELSE 0 END) AS out_of_stock,
       ROUND(AVG(price)) AS avg_price
FROM products
GROUP BY category_id
HAVING COUNT(*) >= 5
ORDER BY total DESC;

Result (top 7 of 31 rows)

category_id total active_count discontinued_count out_of_stock avg_price
18 13 10 3 0 529,754.00
30 13 11 2 0 219,008.00
43 12 9 3 0 277,150.00
3 11 9 2 0 1,719,809.00
31 11 10 1 0 158,482.00
36 11 8 3 0 158,000.00
37 11 7 4 0 41,064.00

28. Comprehensive payment method analysis: Find the count, total

Comprehensive payment method analysis: Find the count, total amount, average amount, refund count, and refund rate (%) per method (displayed in Korean). Only include methods with 1,000+ payments.

Hint 1: This is a combination of CASE for Korean method labels + COUNT(refunded_at) for refund count + HAVING + ORDER BY.

Answer
SELECT CASE method
           WHEN 'card' THEN '신용카드'
           WHEN 'bank_transfer' THEN '계좌이체'
           WHEN 'virtual_account' THEN '가상계좌'
           WHEN 'kakao_pay' THEN '카카오페이'
           WHEN 'naver_pay' THEN '네이버페이'
           WHEN 'point' THEN '포인트'
       END AS method_kr,
       COUNT(*) AS payment_count,
       ROUND(SUM(amount)) AS total_amount,
       ROUND(AVG(amount)) AS avg_amount,
       COUNT(refunded_at) AS refund_count,
       ROUND(COUNT(refunded_at) * 100.0 / COUNT(*), 1) AS refund_rate_pct
FROM payments
GROUP BY method
HAVING COUNT(*) >= 1000
ORDER BY total_amount DESC;

Result (6 rows)

method_kr payment_count total_amount avg_amount refund_count refund_rate_pct
신용카드 16,841 17,004,951,634.00 1,009,735.00 872 5.20
카카오페이 7486 7,563,829,668.00 1,010,397.00 380 5.10
네이버페이 5715 5,998,835,720.00 1,049,665.00 285 5.00
계좌이체 3718 3,753,149,013.00 1,009,454.00 178 4.80
포인트 1921 1,951,369,604.00 1,015,809.00 98 5.10
가상계좌 1876 1,911,359,424.00 1,018,848.00 117 6.20

29. Customer profile completeness analysis: Find the customer co

Customer profile completeness analysis: Find the customer count, percentage (%), average points, and VIP rate (%) per completeness score (0-4). Completeness = number of non-NULL columns among birth_date, gender, last_login_at, and acquisition_channel.

Hint 1: (column IS NOT NULL) returns 1 or 0 in SQLite. Adding all four gives the completeness score.

Answer
SELECT (birth_date IS NOT NULL)
     + (gender IS NOT NULL)
     + (last_login_at IS NOT NULL)
     + (acquisition_channel IS NOT NULL) AS completeness,
       COUNT(*) AS customer_count,
       ROUND(AVG(point_balance)) AS avg_points,
       ROUND(SUM(CASE WHEN grade = 'VIP' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS vip_rate_pct
FROM customers
GROUP BY completeness
ORDER BY completeness;

Result (4 rows)

completeness customer_count avg_points vip_rate_pct
1 5 0.0 0.0
2 143 20,877.00 0.7
3 1247 45,918.00 4.30
4 3835 72,285.00 8.20

30. Comprehensive dashboard: Find the active product count, aver

Comprehensive dashboard: Find the active product count, average price, average margin rate (%), price tier classification, and low-stock product count (stock_qty <= 10) per brand from the products table. Only include brands with 5+ active products, sorted by active product count descending, limited to the top 10.

Hint 1: Use multiple aggregations and CASE simultaneously. This is a combination of WHERE is_active = 1 + GROUP BY brand + HAVING + ORDER BY + LIMIT.

Answer
SELECT brand,
       COUNT(*) AS active_count,
       ROUND(AVG(price)) AS avg_price,
       ROUND(AVG((price - cost_price) * 100.0 / price), 1) AS avg_margin_pct,
       CASE
           WHEN AVG(price) >= 1000000 THEN '프리미엄'
           WHEN AVG(price) >= 300000 THEN '대중'
           ELSE '보급형'
       END AS brand_tier,
       SUM(CASE WHEN stock_qty <= 10 THEN 1 ELSE 0 END) AS low_stock_count
FROM products
WHERE is_active = 1
GROUP BY brand
HAVING COUNT(*) >= 5
ORDER BY active_count DESC
LIMIT 10;

Result (top 7 of 10 rows)

brand active_count avg_price avg_margin_pct brand_tier low_stock_count
Samsung 21 641,800.00 18.50 대중 1
ASUS 21 1,589,552.00 28.00 프리미엄 0
MSI 12 820,292.00 16.80 대중 0
TP-Link 11 128,764.00 30.30 보급형 0
Logitech 11 115,127.00 28.00 보급형 1
LG 11 1,346,836.00 21.20 프리미엄 0
ASRock 9 493,244.00 25.60 대중 0