Day 11 - Pro: Window Functions

Bối cảnh: Hệ thống E-commerce (Thương mại điện tử)


1. OVER() with PARTITION BY

  • Window Functions: Cho phép thực hiện tính toán trên một tập hợp các hàng liên quan đến hàng hiện tại mà không làm gộp chúng thành một hàng duy nhất.

  • PARTITION BY: Chia dữ liệu thành các nhóm (partition) để áp dụng hàm cửa sổ.

  • Ví dụ: Tính tổng doanh thu theo từng phương thức thanh toán:

      SELECT order_id, payment_method, total_amount,
             SUM(total_amount) OVER (PARTITION BY payment_method) AS total_revenue_by_method
      FROM orders;
    

    Kết quả trả về tổng doanh thu của từng phương thức thanh toán cho mỗi đơn hàng.


2. Challenge: OVER() with PARTITION BY

  • Yêu cầu: Viết truy vấn để tính tổng số lượng sản phẩm (total_quantity) đã bán theo từng danh mục (category) từ bảng ordersproducts.

3. Solution: OVER() with PARTITION BY

  • Giải pháp:

      SELECT o.order_id, p.category, o.quantity,
             SUM(o.quantity) OVER (PARTITION BY p.category) AS total_quantity_by_category
      FROM orders o
      INNER JOIN products p ON o.product_id = p.product_id;
    

4. OVER() with ORDER BY

  • ORDER BY trong Window Functions: Sắp xếp dữ liệu trong partition trước khi áp dụng hàm.

  • Ví dụ: Tính tổng doanh thu tích lũy theo thời gian:

      SELECT order_id, order_date, total_amount,
             SUM(total_amount) OVER (ORDER BY order_date) AS cumulative_revenue
      FROM orders;
    

    Kết quả trả về tổng doanh thu tích lũy theo từng ngày đặt hàng.


5. Challenge: OVER() with ORDER BY

  • Yêu cầu: Viết truy vấn để xếp hạng (rank) các sản phẩm theo số lượng bán (quantity) giảm dần.

6. Solution: OVER() with ORDER BY

  • Giải pháp:

      SELECT product_id, quantity,
             RANK() OVER (ORDER BY quantity DESC) AS sales_rank
      FROM orders;
    

7. RANK()

  • RANK(): Xếp hạng các hàng dựa trên giá trị của một cột. Nếu có giá trị trùng nhau, các hàng tiếp theo sẽ nhảy bậc.

  • Ví dụ: Xếp hạng khách hàng theo tổng giá trị đơn hàng:

      SELECT customer_id, total_amount,
             RANK() OVER (ORDER BY total_amount DESC) AS customer_rank
      FROM orders;
    

8. Challenge: RANK()

  • Yêu cầu: Xếp hạng các danh mục sản phẩm (category) theo tổng doanh thu (total_amount) giảm dần.

9. Solution: RANK()

  • Giải pháp:

      SELECT p.category, SUM(o.total_amount) AS total_revenue,
             RANK() OVER (ORDER BY SUM(o.total_amount) DESC) AS revenue_rank
      FROM orders o
      INNER JOIN products p ON o.product_id = p.product_id
      GROUP BY p.category;
    

10. FIRST_VALUE()

  • FIRST_VALUE(): Trả về giá trị đầu tiên trong một partition.

  • Ví dụ: Tìm ngày đặt hàng đầu tiên của mỗi khách hàng:

      SELECT customer_id, order_date,
             FIRST_VALUE(order_date) OVER (PARTITION BY customer_id ORDER BY order_date) AS first_order_date
      FROM orders;
    

11. LEAD & LAG

  • LEAD(): Truy cập giá trị của hàng tiếp theo trong partition.

  • LAG(): Truy cập giá trị của hàng trước đó trong partition.

  • Ví dụ: So sánh doanh thu giữa các tháng:

      SELECT EXTRACT(MONTH FROM order_date) AS month,
             SUM(total_amount) AS monthly_revenue,
             LAG(SUM(total_amount)) OVER (ORDER BY EXTRACT(MONTH FROM order_date)) AS prev_month_revenue,
             LEAD(SUM(total_amount)) OVER (ORDER BY EXTRACT(MONTH FROM order_date)) AS next_month_revenue
      FROM orders
      GROUP BY month;
    

12. Challenge: LEAD & LAG

  • Yêu cầu: Tính chênh lệch doanh thu giữa tháng hiện tại và tháng trước đó.

13. Solution: LEAD & LAG

  • Giải pháp:

      WITH monthly_revenue AS (
        SELECT EXTRACT(MONTH FROM order_date) AS month,
               SUM(total_amount) AS current_month_revenue
        FROM orders
        GROUP BY month
      )
      SELECT month, current_month_revenue,
             LAG(current_month_revenue) OVER (ORDER BY month) AS prev_month_revenue,
             current_month_revenue - LAG(current_month_revenue) OVER (ORDER BY month) AS revenue_diff
      FROM monthly_revenue;
    

14. Today's slides

  • Tổng kết các hàm cửa sổ: PARTITION BY, ORDER BY, RANK(), FIRST_VALUE(), LEAD(), LAG().

  • Slide tham khảo cung cấp ví dụ chi tiết và ứng dụng trong hệ thống E-commerce.


15. Today's summary

  • Hôm nay, bạn đã học:

    • Cách sử dụng PARTITION BYORDER BY trong Window Functions.

    • Cách xếp hạng dữ liệu với RANK().

    • Cách truy cập giá trị đầu tiên (FIRST_VALUE()) và so sánh dữ liệu giữa các hàng (LEAD(), LAG()).

  • Hẹn gặp lại bạn vào ngày 12 với chủ đề Pro: Grouping sets, rollups, self-joins!


16. Today's challenges

  • Thử thách 1: Tính tỷ lệ phần trăm đóng góp doanh thu của từng sản phẩm trong tổng doanh thu của danh mục.

  • Thử thách 2: Xếp hạng khách hàng (customer_id) theo tổng số lượng đơn hàng (order_count) giảm dần.

  • Thử thách 3: Tìm khoảng thời gian (số ngày) giữa hai đơn hàng liên tiếp của cùng một khách hàng.