ปัญหา: GROUP BY รวม NULL ทั้งหมดเป็นกลุ่มเดียว
พฤติกรรมมาตรฐานของ SQL: GROUP BY column จะรวมค่า NULL ทั้งหมดเป็นกลุ่มเดียว เพราะ NULL = NULL เป็น UNKNOWN (ไม่ใช่ TRUE) แต่ GROUP BY จัดว่า "เท่ากัน" สำหรับการจัดกลุ่ม
สร้างตารางและข้อมูล (มี NULL 2 แถว)
mysql> CREATE TABLE DemoTable1511 (
-> Id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> FirstName VARCHAR(20)
-> );
Query OK, 0 rows affected (1.97 sec)
mysql> INSERT INTO DemoTable1511(FirstName) VALUES
-> ('John'), ('Robert'), ('Mike'), ('Robert'), (NULL), (NULL), ('Mike');
Query OK, 7 rows affected
ข้อมูลทั้งหมด
+----+-----------+ | Id | FirstName | +----+-----------+ | 1 | John | | 2 | Robert | | 3 | Mike | | 4 | Robert | | 5 | NULL | | 6 | NULL | | 7 | Mike | +----+-----------+
GROUP BY ปกติ: NULL รวมเป็น 1 กลุ่ม
mysql> SELECT MIN(Id) AS Id, FirstName FROM DemoTable1511 GROUP BY FirstName ORDER BY Id; +------+-----------+ | Id | FirstName | +------+-----------+ | 1 | John | | 2 | Robert | | 3 | Mike | | 5 | NULL | <-- NULL 2 แถวรวมเป็น 1 +------+-----------+
วิธีแก้: ใช้ IFNULL(FirstName, Id) ใน GROUP BY
mysql> SELECT MIN(Id) AS Id, FirstName
-> FROM DemoTable1511
-> GROUP BY FirstName, IFNULL(FirstName, Id)
-> ORDER BY Id;
ผลลัพธ์: NULL แยกเป็น 2 กลุ่ม (Id 5 และ 6)
+------+-----------+ | Id | FirstName | +------+-----------+ | 1 | John | | 2 | Robert | | 3 | Mike | | 5 | NULL | | 6 | NULL | +------+-----------+
คำอธิบาย IFNULL(FirstName, Id)
- ถ้า
FirstName IS NOT NULL→ คืนFirstName→ จัดกลุ่มตามชื่อปกติ - ถ้า
FirstName IS NULL→ คืนId(Unique) → แต่ละ NULL ได้ค่า Id ต่างกัน → แยกกลุ่ม
วิธีอื่น: ใช้ CONCAT กับ PK
GROUP BY CONCAT(FirstName, '#', Id)
-- หรือ
GROUP BY COALESCE(FirstName, CONCAT('NULL_', Id))
⚠️ ข้อควรระวัง
- วิธีนี้ทำให้ NULL ไม่ถูกรวมกลุ่ม แต่ เปลี่ยน Semantics ของ GROUP BY (แต่ละ NULL กลายเป็นกลุ่มตัวเอง)
- ใช้เฉพาะเมื่อต้องการ "แยกแถว NULL" จริงๆ (เช่น Audit Log, Raw Data)
- ปกติแล้ว NULL ควรเป็นกลุ่มเดียวกัน (Standard SQL Behavior)
MySQL 8.0: ใช้ GROUPING SETS / ROLLUP (Advanced)
SELECT FirstName, COUNT(*) FROM DemoTable1511 GROUP BY ROLLUP(FirstName); -- รวม Total row ด้วย