MySQL行列轉(zhuǎn)換常見的操作方法詳解
前言
行列轉(zhuǎn)換是SQL中常見的操作,主要包括兩種類型:行轉(zhuǎn)列(PIVOT)和列轉(zhuǎn)行(UNPIVOT)。MySQL雖然沒有直接的PIVOT/UNPIVOT語法,但可以通過條件聚合和UNION ALL等方式實(shí)現(xiàn)。
一、行轉(zhuǎn)列(PIVOT)
行轉(zhuǎn)列是將行數(shù)據(jù)轉(zhuǎn)換為列數(shù)據(jù),通常用于將分類數(shù)據(jù)作為列名展示。
示例場景:學(xué)生成績表行轉(zhuǎn)列
1. 創(chuàng)建原始表
CREATE TABLE student_scores (
student_id INT,
student_name VARCHAR(50),
subject VARCHAR(50),
score INT
);
INSERT INTO student_scores VALUES
(1, '張三', '數(shù)學(xué)', 90),
(1, '張三', '語文', 85),
(1, '張三', '英語', 92),
(2, '李四', '數(shù)學(xué)', 88),
(2, '李四', '語文', 90),
(2, '李四', '英語', 87),
(3, '王五', '數(shù)學(xué)', 95),
(3, '王五', '語文', 78),
(3, '王五', '英語', 85);2. 行轉(zhuǎn)列實(shí)現(xiàn)方法
使用條件聚合函數(shù):
SELECT
student_id,
student_name,
MAX(CASE WHEN subject = '數(shù)學(xué)' THEN score ELSE NULL END) AS '數(shù)學(xué)',
MAX(CASE WHEN subject = '語文' THEN score ELSE NULL END) AS '語文',
MAX(CASE WHEN subject = '英語' THEN score ELSE NULL END) AS '英語'
FROM student_scores
GROUP BY student_id, student_name;結(jié)果:
+------------+--------------+--------+--------+--------+ | student_id | student_name | 數(shù)學(xué) | 語文 | 英語 | +------------+--------------+--------+--------+--------+ | 1 | 張三 | 90 | 85 | 92 | | 2 | 李四 | 88 | 90 | 87 | | 3 | 王五 | 95 | 78 | 85 | +------------+--------------+--------+--------+--------+

二、列轉(zhuǎn)行(UNPIVOT)
列轉(zhuǎn)行是將列數(shù)據(jù)轉(zhuǎn)換為行數(shù)據(jù),通常用于將多列數(shù)據(jù)轉(zhuǎn)換為鍵值對形式。
示例場景:銷售數(shù)據(jù)列轉(zhuǎn)行
1. 創(chuàng)建原始表
CREATE TABLE sales_data (
id INT,
product_name VARCHAR(50),
q1_sales INT,
q2_sales INT,
q3_sales INT,
q4_sales INT
);
INSERT INTO sales_data VALUES
(1, '產(chǎn)品A', 120, 150, 180, 200),
(2, '產(chǎn)品B', 90, 110, 130, 150),
(3, '產(chǎn)品C', 200, 220, 240, 260);2. 列轉(zhuǎn)行實(shí)現(xiàn)方法
使用UNION ALL:
SELECT
id,
product_name,
'Q1' AS quarter,
q1_sales AS sales
FROM sales_data
UNION ALL
SELECT
id,
product_name,
'Q2' AS quarter,
q2_sales AS sales
FROM sales_data
UNION ALL
SELECT
id,
product_name,
'Q3' AS quarter,
q3_sales AS sales
FROM sales_data
UNION ALL
SELECT
id,
product_name,
'Q4' AS quarter,
q4_sales AS sales
FROM sales_data
ORDER BY id, quarter;結(jié)果:
+----+--------------+---------+-------+ | id | product_name | quarter | sales | +----+--------------+---------+-------+ | 1 | 產(chǎn)品A | Q1 | 120 | | 1 | 產(chǎn)品A | Q2 | 150 | | 1 | 產(chǎn)品A | Q3 | 180 | | 1 | 產(chǎn)品A | Q4 | 200 | | 2 | 產(chǎn)品B | Q1 | 90 | | 2 | 產(chǎn)品B | Q2 | 110 | | 2 | 產(chǎn)品B | Q3 | 130 | | 2 | 產(chǎn)品B | Q4 | 150 | | 3 | 產(chǎn)品C | Q1 | 200 | | 3 | 產(chǎn)品C | Q2 | 220 | | 3 | 產(chǎn)品C | Q3 | 240 | | 3 | 產(chǎn)品C | Q4 | 260 | +----+--------------+---------+-------+

三、動態(tài)行列轉(zhuǎn)換
當(dāng)列名不確定或經(jīng)常變化時,可以使用動態(tài)SQL實(shí)現(xiàn)行列轉(zhuǎn)換。
-- 創(chuàng)建存儲過程實(shí)現(xiàn)動態(tài)行轉(zhuǎn)列
DELIMITER //
CREATE PROCEDURE dynamic_pivot()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE col_name VARCHAR(50);
DECLARE col_list TEXT DEFAULT '';
DECLARE cur CURSOR FOR
SELECT DISTINCT subject FROM student_scores;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO col_name;
IF done THEN
LEAVE read_loop;
END IF;
SET col_list = CONCAT(col_list,
IF(col_list = '', '', ', '),
'MAX(CASE WHEN subject = ''', col_name, ''' THEN score ELSE NULL END) AS ''', col_name, '''');
END LOOP;
CLOSE cur;
SET @sql = CONCAT('SELECT student_id, student_name, ', col_list, ' FROM student_scores GROUP BY student_id, student_name');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
-- 調(diào)用存儲過程
CALL dynamic_pivot();四、性能優(yōu)化建議
- 對于大型數(shù)據(jù)集的列轉(zhuǎn)行,考慮使用臨時表替代UNION ALL
- 在行轉(zhuǎn)列時,確保GROUP BY子句包含所有非聚合列
- 為常用轉(zhuǎn)換創(chuàng)建視圖,提高查詢效率
- 在動態(tài)SQL中,注意防止SQL注入
五、實(shí)際應(yīng)用場景
- 報表生成:將行數(shù)據(jù)轉(zhuǎn)換為適合報表展示的列格式
- 數(shù)據(jù)透視:分析不同維度的數(shù)據(jù)關(guān)系
- ETL過程:數(shù)據(jù)清洗和轉(zhuǎn)換
- 數(shù)據(jù)展示:將數(shù)據(jù)庫格式轉(zhuǎn)換為前端需要的格式
到此這篇關(guān)于MySQL行列轉(zhuǎn)換常見操作方法的文章就介紹到這了,更多相關(guān)MySQL行列轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql group by 多個行轉(zhuǎn)換為一個字段
本文主要介紹了mysql group by 多個行轉(zhuǎn)換為一個字段,可以使用聚合函數(shù)GROUP_CONCAT()函數(shù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-08-08
MySQL中使用PROFILING來查看SQL執(zhí)行流程的實(shí)現(xiàn)步驟
在MySQL中,PROFILING功能提供了一種方式來分析SQL語句的執(zhí)行時間,包括查詢執(zhí)行的各個階段,如發(fā)送、解析、優(yōu)化、執(zhí)行等,這對于診斷性能問題非常有用,本文給大家介紹了MySQL中使用PROFILING來查看SQL執(zhí)行流程的實(shí)現(xiàn)步驟,需要的朋友可以參考下2024-07-07
MySQL的備份工具mysqldump的基礎(chǔ)使用命令總結(jié)
這篇文章主要介紹了MySQL的備份工具mysqldump的基礎(chǔ)使用命令總結(jié),除了基本的導(dǎo)入導(dǎo)出,還介紹了其他一些命令參數(shù)的用法,需要的朋友可以參考下2015-12-12
php運(yùn)行提示Can''t connect to MySQL server on ''localhost''的解決方法
有些時候我們運(yùn)行php的時候,頁面提示Can't connect to MySQL server on 'localhost',那么就需要參考下面的方法來解決。2011-06-06
MySQL系列之redo log、undo log和binlog詳解
這篇文章主要介紹了MySQL系列之redo log、undo log和binlog詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12

