Clause GROUP BY คืออะไร?
ในบทเรียนที่ผ่านมา เราได้เรียนรู้เกี่ยวกับฟังก์ชัน `MIN()` และ `MAX()` ซึ่งช่วยให้เราหาค่าที่น้อยที่สุดและมากที่สุดในคอลัมน์ต่างๆ ได้ แต่ถ้าเราต้องการหาค่าเหล่านี้ในแต่ละกลุ่มของข้อมูลล่ะ? นั่นแหละคือที่มาของ `GROUP BY` clause!
`GROUP BY` clause ใน MySQL ใช้เพื่อจัดกลุ่มแถวที่มีค่าเหมือนกันในหนึ่งหรือหลายคอลัมน์ให้เป็นกลุ่มเดียว ทำให้เราสามารถทำการคำนวณ (โดยใช้ Aggregate Functions เช่น `COUNT()`, `SUM()`, `AVG()`, `MIN()`, `MAX()`) กับแต่ละกลุ่มที่ได้
ไวยากรณ์ของ GROUP BY
SELECT column1, column2, ... , aggregate_function(column_name)
FROM table_name
WHERE condition
GROUP BY column1, column2, ...
ORDER BY column1, column2, ...;
คำอธิบาย:
- `SELECT`: เลือกคอลัมน์ที่ต้องการแสดงผล รวมถึงฟังก์ชัน Aggregate ที่จะใช้
- `FROM`: ระบุตารางที่ต้องการดึงข้อมูล
- `WHERE`: (Optional) ใช้กรองข้อมูลก่อนที่จะทำการจัดกลุ่ม
- `GROUP BY`: ระบุคอลัมน์ที่ใช้ในการจัดกลุ่มข้อมูล
- `ORDER BY`: (Optional) ใช้เรียงลำดับผลลัพธ์
ตัวอย่างการใช้งาน GROUP BY
สมมติว่าเรามีตาราง `products` ที่เก็บข้อมูลสินค้า:
CREATE TABLE products (
product_id INT PRIMARY KEY,
product_name VARCHAR(255),
category VARCHAR(255),
price DECIMAL(10, 2)
);
INSERT INTO products (product_id, product_name, category, price) VALUES
(1, 'เสื้อยืด', 'เสื้อผ้า', 250.00),
(2, 'กางเกงยีนส์', 'เสื้อผ้า', 800.00),
(3, 'รองเท้าผ้าใบ', 'รองเท้า', 1200.00),
(4, 'เสื้อเชิ้ต', 'เสื้อผ้า', 400.00),
(5, 'รองเท้าแตะ', 'รองเท้า', 300.00),
(6, 'หมวก', 'เครื่องประดับ', 150.00);
ตัวอย่างที่ 1: หาจำนวนสินค้าในแต่ละประเภท
SELECT category, COUNT(*) AS total_products
FROM products
GROUP BY category;
ผลลัพธ์:
+-----------------+----------------+
| category | total_products |
+-----------------+----------------+
| เครื่องประดับ | 1 |
| รองเท้า | 2 |
| เสื้อผ้า | 3 |
+-----------------+----------------+
คำสั่ง SQL นี้จะจัดกลุ่มสินค้าตาม `category` และใช้ฟังก์ชัน `COUNT(*)` เพื่อนับจำนวนสินค้าในแต่ละกลุ่ม จากนั้นแสดงผลลัพธ์เป็นประเภทสินค้า (`category`) และจำนวนสินค้ารวม (`total_products`) ในแต่ละประเภท
ตัวอย่างที่ 2: หาค่าเฉลี่ยราคาสินค้าในแต่ละประเภท
SELECT category, AVG(price) AS average_price
FROM products
GROUP BY category;
ผลลัพธ์:
+-----------------+----------------+
| category | average_price |
+-----------------+----------------+
| เครื่องประดับ | 150.0000 |
| รองเท้า | 750.0000 |
| เสื้อผ้า | 483.3333 |
+-----------------+----------------+
คำสั่ง SQL นี้จะจัดกลุ่มสินค้าตาม `category` และใช้ฟังก์ชัน `AVG(price)` เพื่อหาค่าเฉลี่ยของราคาสินค้าในแต่ละกลุ่ม จากนั้นแสดงผลลัพธ์เป็นประเภทสินค้า (`category`) และราคาเฉลี่ย (`average_price`) ในแต่ละประเภท
ตัวอย่างที่ 3: หาค่าต่ำสุดและสูงสุดของราคาสินค้าในแต่ละประเภท
SELECT category, MIN(price) AS min_price, MAX(price) AS max_price
FROM products
GROUP BY category;
ผลลัพธ์:
+-----------------+-----------+-----------+
| category | min_price | max_price |
+-----------------+-----------+-----------+
| เครื่องประดับ | 150.00 | 150.00 |
| รองเท้า | 300.00 | 1200.00 |
| เสื้อผ้า | 250.00 | 800.00 |
+-----------------+-----------+-----------+
คำสั่ง SQL นี้จะจัดกลุ่มสินค้าตาม `category` และใช้ฟังก์ชัน `MIN(price)` และ `MAX(price)` เพื่อหาราคาต่ำสุดและสูงสุดในแต่ละกลุ่ม จากนั้นแสดงผลลัพธ์เป็นประเภทสินค้า (`category`), ราคาสินค้าต่ำสุด (`min_price`) และราคาสินค้าสูงสุด (`max_price`) ในแต่ละประเภท
ข้อควรระวังในการใช้ GROUP BY
- คอลัมน์ที่ไม่ได้อยู่ใน Aggregate Function ต้องอยู่ใน GROUP BY: หากคุณเลือกคอลัมน์ใดๆ ที่ไม่ได้ใช้ใน Aggregate Function (เช่น `COUNT()`, `SUM()`, `AVG()`, `MIN()`, `MAX()`) คอลัมน์นั้นจะต้องอยู่ใน `GROUP BY` clause ด้วย มิฉะนั้น MySQL จะแสดงข้อผิดพลาด (ขึ้นอยู่กับการตั้งค่า `sql_mode`)
- ลำดับของคอลัมน์ใน GROUP BY: ลำดับของคอลัมน์ใน `GROUP BY` clause มีผลต่อการจัดกลุ่มข้อมูล หากสลับลำดับ อาจได้ผลลัพธ์ที่แตกต่างกัน
- การใช้ WHERE clause ร่วมกับ GROUP BY: `WHERE` clause จะถูกประมวลผลก่อน `GROUP BY` ดังนั้น `WHERE` จะใช้เพื่อกรองแถว *ก่อน* ที่จะทำการจัดกลุ่ม
กรณีใช้งานจริงและข้อผิดพลาดที่พบบ่อย
กรณีใช้งานจริง: พิจารณาตาราง `orders` ที่เก็บข้อมูลการสั่งซื้อ:
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
total_amount DECIMAL(10, 2)
);
INSERT INTO orders (order_id, customer_id, order_date, total_amount) VALUES
(1, 101, '2023-10-26', 150.00),
(2, 102, '2023-10-26', 200.00),
(3, 101, '2023-10-27', 100.00),
(4, 103, '2023-10-27', 300.00),
(5, 102, '2023-10-28', 250.00);
เราสามารถใช้ `GROUP BY` เพื่อหาจำนวนการสั่งซื้อและยอดรวมการสั่งซื้อของลูกค้าแต่ละราย:
SELECT customer_id, COUNT(*) AS total_orders, SUM(total_amount) AS total_spent
FROM orders
GROUP BY customer_id;
ข้อผิดพลาดที่พบบ่อย:
ข้อผิดพลาด: "Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'your_database.orders.order_id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by"
สาเหตุ: ข้อผิดพลาดนี้เกิดขึ้นเมื่อคุณเลือกคอลัมน์ที่ไม่ใช่ Aggregate Function และไม่ได้อยู่ใน `GROUP BY` clause ในขณะที่ `sql_mode` ถูกตั้งค่าเป็น `only_full_group_by` (ซึ่งเป็นค่าเริ่มต้นใน MySQL 5.7.5 ขึ้นไป)
วิธีแก้ไข:
- เพิ่มคอลัมน์ที่เลือกทั้งหมดที่ไม่ใช่ Aggregate Function ไปยัง `GROUP BY` clause
- ใช้ Aggregate Function กับคอลัมน์นั้น (ถ้าเหมาะสม)
- ปิดใช้งาน `only_full_group_by` ใน MySQL configuration (ไม่แนะนำ เว้นแต่คุณจะเข้าใจผลกระทบ)
ตัวอย่างเช่น หากเราต้องการแสดง `order_id` ใน query ข้างต้น เราจะต้องเพิ่ม `order_id` ไปยัง `GROUP BY` (ซึ่งอาจไม่สมเหตุสมผลในกรณีนี้) หรือใช้ Aggregate Function กับ `order_id` เช่น `MIN(order_id)` หรือ `MAX(order_id)`
สรุป
`GROUP BY` clause เป็นเครื่องมือที่ทรงพลังในการจัดกลุ่มข้อมูลและทำการวิเคราะห์ใน MySQL ช่วยให้เราสามารถสรุปข้อมูลและหาข้อมูลเชิงลึกจากฐานข้อมูลของเราได้ เมื่อใช้ร่วมกับ Aggregate Functions เราสามารถหาค่าต่างๆ เช่น จำนวน, ค่าเฉลี่ย, ค่าต่ำสุด, และค่าสูงสุด ในแต่ละกลุ่มของข้อมูลได้อย่างง่ายดาย อย่าลืมทำความเข้าใจกฎและข้อควรระวังในการใช้งาน `GROUP BY` เพื่อหลีกเลี่ยงข้อผิดพลาดที่พบบ่อย
ในบทเรียนถัดไป เราจะเรียนรู้เกี่ยวกับ `HAVING` clause ซึ่งใช้เพื่อกรองกลุ่มข้อมูลที่ได้จาก `GROUP BY` clause