Kodokon kodokon.com

HAVING และการรวมกลุ่มขั้นสูง

กรองข้อมูลหลังการรวมกลุ่มด้วย HAVING และพลิกข้อมูลของคุณด้วย CASE WHEN ภายในฟังก์ชันการรวมกลุ่ม

8 นาที · 3 คำถาม

เปิดบทเรียนนี้ใน Kodokon

คุณรู้จัก GROUP BY อยู่แล้ว บทเรียนนี้จะพูดถึงสิ่งที่แยกคิวรีที่ถูกต้องออกจากคิวรีระดับมืออาชีพ ได้แก่ การกรองหลังการรวมกลุ่ม, การรวมกลุ่มแบบมีเงื่อนไข และความเข้าใจอย่างถ่องแท้เกี่ยวกับลำดับการประเมินผล ในการฝึกฝน ให้เปิด sqliteonline.com (เอนจิน SQLite) หรือเปิด sqlite3 ในเทอร์มินัล แต่ละบทเรียนจะให้คำสั่ง CREATE TABLE และ INSERT ที่คุณต้องใช้ จงคัดลอกชุดข้อมูลนี้ก่อนรันตัวอย่าง

SQL
CREATE TABLE orders (
  id INTEGER PRIMARY KEY,
  customer TEXT NOT NULL,
  category TEXT NOT NULL,
  amount REAL NOT NULL,
  status TEXT NOT NULL
);

INSERT INTO orders (customer, category, amount, status)
VALUES
  ('alice', 'books', 42.0, 'paid'),
  ('alice', 'games', 55.0, 'paid'),
  ('alice', 'books', 18.5, 'refunded'),
  ('bruno', 'games', 70.0, 'paid'),
  ('bruno', 'books', 12.0, 'paid'),
  ('chloe', 'games', 95.0, 'paid'),
  ('chloe', 'books', 30.0, 'paid'),
  ('david', 'books', 8.0, 'refunded');
ชุดข้อมูลสำหรับบทเรียนนี้ รันมันก่อน

ลำดับการประเมินผลเชิง ตรรกะ คือกุญแจสำคัญ ได้แก่ FROMWHEREGROUP BYHAVINGSELECTORDER BY โดย WHERE กรอง แถว ก่อนการจัดกลุ่ม ส่วน HAVING กรอง กลุ่ม หลังจากคำนวณค่าการรวมกลุ่มเสร็จแล้ว นั่นคือเหตุผลที่ WHERE SUM(amount) > 90 ผิดกฎ เพราะในขั้น WHERE ยังไม่มีผลรวมอยู่เลย ในที่นี้ เราเก็บเฉพาะลูกค้าที่มียอดชำระเงินรวมเกิน 90 (คาดว่า: alice และ chloe)

SQL
SELECT customer,
       COUNT(*) AS nb_orders,
       SUM(amount) AS total
FROM orders
WHERE status = 'paid'
GROUP BY customer
HAVING SUM(amount) > 90;
WHERE ตัดแถวออก ส่วน HAVING ตัดกลุ่มออก

รูปแบบที่ต้องรู้อันที่สองคือ การรวมกลุ่มแบบมีเงื่อนไข (conditional aggregate) ด้วยการสอด CASE WHEN ไว้ภายใน SUM หรือ COUNT คุณสามารถคำนวณหลายเมตริกได้ในการอ่านตารางเพียงรอบเดียว ในขณะที่มือใหม่จะต้องรันคิวรีแยกกันสามครั้ง นี่คือเทคนิคมาตรฐานสำหรับการพลิกแถวให้กลายเป็นคอลัมน์

SQL
SELECT customer,
  SUM(CASE WHEN category = 'books'
      THEN amount ELSE 0 END) AS books_total,
  SUM(CASE WHEN category = 'games'
      THEN amount ELSE 0 END) AS games_total
FROM orders
WHERE status = 'paid'
GROUP BY customer;
พลิกแถว → คอลัมน์ในการอ่านครั้งเดียว

ทดสอบความรู้

ตรวจสอบว่าคุณจำประเด็นสำคัญของบทเรียนนี้ได้ครบถ้วน

  1. เอนจินประเมินคำสั่งเหล่านี้ตามลำดับตรรกะแบบใด?
    • WHERE → GROUP BY → HAVING
    • HAVING → WHERE → GROUP BY
    • GROUP BY → HAVING → WHERE
  2. เงื่อนไขใดควรอยู่ใน WHERE แทนที่จะเป็น HAVING?
    • SUM(amount) > 100
    • status = 'paid'
    • COUNT(*) >= 2
  3. SUM(CASE WHEN category = 'books' THEN amount ELSE 0 END) คำนวณอะไร?
    • ยอดรวมของคำสั่งซื้อทั้งหมด
    • ยอดรวมเฉพาะแถวในหมวด 'books' เท่านั้น
    • จำนวนแถวในหมวด 'books'
    • ยอดรวมของแถวที่อยู่นอกหมวด 'books'