Sử dụng IF() hoặc CASE WHEN trong SELECT kết hợp GROUP BY nhiều cột để tạo cột flag chỉ thị điều kiện.
Cú pháp
SELECT cột_nhóm1, cột_nhóm2, IF(điều_kiện, 1, 0) AS flag FROM tên_bảng GROUP BY cột_nhóm1, cột_nhóm2;
Ví dụ minh họa
Tạo bảng đơn hàng:
mysql> CREATE TABLE MultipleGroupByDemo (
-> Id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> CustomerId INT,
-> ProductName VARCHAR(100)
-> );
Query OK, 0 rows affected (0.59 sec)
Chèn dữ liệu:
mysql> INSERT INTO MultipleGroupByDemo(CustomerId, ProductName) VALUES
-> (1000, 'Product-1'), (1001, 'Product-2'), (1001, 'Product-2'), (1001, 'Product-2'),
-> (1002, 'Product-3'), (1002, 'Product-3'), (1003, 'Product-4');
Xem dữ liệu:
mysql> SELECT * FROM MultipleGroupByDemo;
+----+------------+-------------+ | Id | CustomerId | ProductName | +----+------------+-------------+ | 1 | 1000 | Product-1 | | 2 | 1001 | Product-2 | | 3 | 1001 | Product-2 | | 4 | 1001 | Product-2 | | 5 | 1002 | Product-3 | | 6 | 1002 | Product-3 | | 7 | 1003 | Product-4 | +----+------------+-------------+
GROUP BY ProductName, CustomerId với flag Product-2:
mysql> SELECT CustomerId, IF(ProductName = 'Product-2', 1, 0)
-> FROM MultipleGroupByDemo
-> GROUP BY ProductName, CustomerId;
+------------+---------------------------------------+ | CustomerId | if(ProductName = 'Product-2', 1, 0) | +------------+---------------------------------------+ | 1000 | 0 | | 1001 | 1 | | 1002 | 0 | | 1003 | 0 |
Cách viết chuẩn hơn: MAX(IF()) với GROUP BY đơn
mysql> SELECT CustomerId, MAX(IF(ProductName = 'Product-2', 1, 0))
-> FROM MultipleGroupByDemo
-> GROUP BY CustomerId;
+------------+-----------------------------------------+ | CustomerId | MAX(IF(ProductName = 'Product-2', 1, 0)) | +------------+-----------------------------------------+ | 1000 | 0 | | 1001 | 1 | | 1002 | 0 | | 1003 | 0 | +------------+-----------------------------------------+
Cách này nhóm theo CustomerId, kiểm tra xem khách hàng đó có mua Product-2 không (1=có, 0=không).
Mở rộng: Pivot table (cột động)
SELECT CustomerId,
MAX(IF(ProductName = 'Product-1', 1, 0)) AS `Product-1`,
MAX(IF(ProductName = 'Product-2', 1, 0)) AS `Product-2`,
MAX(IF(ProductName = 'Product-3', 1, 0)) AS `Product-3`,
MAX(IF(ProductName = 'Product-4', 1, 0)) AS `Product-4`
FROM MultipleGroupByDemo
GROUP BY CustomerId;
+------------+-----------+-----------+-----------+-----------+ | CustomerId | Product-1 | Product-2 | Product-3 | Product-4 | +------------+-----------+-----------+-----------+-----------+ | 1000 | 1 | 0 | 0 | 0 | | 1001 | 0 | 1 | 0 | 0 | | 1002 | 0 | 0 | 1 | 0 | | 1003 | 0 | 0 | 0 | 1 | +------------+-----------+-----------+-----------+-----------+
MySQL 8.0+: CTE + Window Function
WITH ranked AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY CustomerId, ProductName ORDER BY Id) AS rn
FROM MultipleGroupByDemo
)
SELECT CustomerId, ProductName FROM ranked WHERE rn = 1;