Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> MySQL

Hiển thị điểm học sinh trong một cột dựa trên môn học trong MySQL?

Unpivot: Chuyển cột môn học thành hàng (cột đơn) với UNION ALL trong MySQL

Khi dữ liệu lưu theo định dạng rộng (wide format: mỗi môn một cột), dùng UNION ALL để chuyển sang định dạng dài (long format: một cột SubjectName, một cột Score) để dễ báo cáo, phân tích.

Ví dụ minh họa

Tạo bảng DemoTable729 (định dạng rộng):

mysql> CREATE TABLE DemoTable729 (
    StudentId INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    StudentName VARCHAR(100),
    MySQLMarks INT,
    CMarks INT,
    JavaMarks INT
);
Query OK, 0 rows affected (0.40 sec)

Chèn dữ liệu:

mysql> INSERT INTO DemoTable729(StudentName,MySQLMarks,CMarks,JavaMarks) VALUES('Chris',94,67,75);
Query OK, 1 row affected (0.21 sec)
mysql> INSERT INTO DemoTable729(StudentName,MySQLMarks,CMarks,JavaMarks) VALUES('Robert',45,99,54);
Query OK, 1 row affected (0.18 sec)
mysql> INSERT INTO DemoTable729(StudentName,MySQLMarks,CMarks,JavaMarks) VALUES('David',57,89,43);
Query OK, 1 row affected (0.12 sec)

Xem dữ liệu gốc (3 hàng, 5 cột):

mysql> SELECT * FROM DemoTable729;
+-----------+-------------+------------+--------+-----------+
| StudentId | StudentName | MySQLMarks | CMarks | JavaMarks |
+-----------+-------------+------------+--------+-----------+
| 1         | Chris       | 94         | 67     | 75        |
| 2         | Robert      | 45         | 99     | 54        |
| 3         | David       | 57         | 89     | 43        |
+-----------+-------------+------------+--------+-----------+
3 rows in set (0.00 sec)

Chuyển sang định dạng dài (9 hàng, 4 cột) với UNION ALL:

mysql> SELECT StudentId, StudentName, 'MySQL' AS SubjectName, MySQLMarks AS Score FROM DemoTable729
UNION ALL
SELECT StudentId, StudentName, 'C' AS SubjectName, CMarks AS Score FROM DemoTable729
UNION ALL
SELECT StudentId, StudentName, 'Java' AS SubjectName, JavaMarks AS Score FROM DemoTable729;

Kết quả:

+-----------+-------------+-------------+-------+
| StudentId | StudentName | SubjectName | Score |
+-----------+-------------+-------------+-------+
| 1         | Chris       | MySQL       | 94    |
| 2         | Robert      | MySQL       | 45    |
| 3         | David       | MySQL       | 57    |
| 1         | Chris       | C           | 67    |
| 2         | Robert      | C           | 99    |
| 3         | David       | C           | 89    |
| 1         | Chris       | Java        | 75    |
| 2         | Robert      | Java        | 54    |
| 3         | David       | Java        | 43    |
+-----------+-------------+-------------+-------+
9 rows in set (0.00 sec)

UNION vs UNION ALL

Toán tửXử lý trùng lặpHiệu suấtKhi nào dùng
UNION ALLGiữ tất cả (kहông distinct)Nhanh hơnBiết chắc không trùng / muốn giữ trùng
UNIONLoại bỏ trùng (DISTINCT)Chậm hơn (sort/hash)Cần kết quả duy nhất

Ở đây dùng UNION ALL vì mỗi SELECT trả về SubjectName khác nhau → không bao giờ trùng.

Ứng dụng thực tế

  • Báo cáo điểm theo môn, học kỳ
  • Chuẩn bị dữ liệu cho BI tool (Power BI, Tableau) - thích định dạng dài
  • Pivot ngược lại (long → wide): dùng CASE WHEN + GROUP BY hoặc PIVOT (MySQL không có PIVOT native)

MySQL 8.0+: CTE làm code sạch hơn

WITH unpivoted AS (
    SELECT StudentId, StudentName, 'MySQL' AS Subject, MySQLMarks AS Score FROM DemoTable729
    UNION ALL SELECT StudentId, StudentName, 'C', CMarks FROM DemoTable729
    UNION ALL SELECT StudentId, StudentName, 'Java', JavaMarks FROM DemoTable729
)
SELECT * FROM unpivoted ORDER BY StudentId, Subject;