当前位置: 首页 > news >正文

MySQL 行转列与列转行的实现方式

在 MySQL 中,行转列(Pivot)和列转行(Unpivot)是常见的数据转换需求。以下是这两种操作的实现方式:

行转列(Pivot)

行转列是将多行数据转换为一行多列的操作。

1. 使用 CASE WHEN 和聚合函数

这是最常用的行转列方法,适用于已知转换后列名的情况。

-- 示例数据
CREATE TABLE sales (year INT,quarter INT,amount DECIMAL(10,2)
);INSERT INTO sales VALUES
(2020, 1, 1000),
(2020, 2, 1500),
(2020, 3, 2000),
(2020, 4, 1800),
(2021, 1, 1200),
(2021, 2, 1600),
(2021, 3, 2200),
(2021, 4, 1900);-- 行转列:将季度数据转换为列
SELECT year,SUM(CASE WHEN quarter = 1 THEN amount ELSE 0 END) AS Q1,SUM(CASE WHEN quarter = 2 THEN amount ELSE 0 END) AS Q2,SUM(CASE WHEN quarter = 3 THEN amount ELSE 0 END) AS Q3,SUM(CASE WHEN quarter = 4 THEN amount ELSE 0 END) AS Q4,SUM(amount) AS Total
FROM sales
GROUP BY year;

2. 使用 IF 函数

与 CASE WHEN 类似,但语法更简洁:

SELECT year,SUM(IF(quarter = 1, amount, 0)) AS Q1,SUM(IF(quarter = 2, amount, 0)) AS Q2,SUM(IF(quarter = 3, amount, 0)) AS Q3,SUM(IF(quarter = 4, amount, 0)) AS Q4,SUM(amount) AS Total
FROM sales
GROUP BY year;

3. 动态行转列(当列名不确定时)

当需要转换的列值不固定时,可以使用存储过程动态生成 SQL:

DELIMITER //CREATE PROCEDURE dynamic_pivot()
BEGINSET @sql = NULL;-- 获取所有不同的季度值SELECT GROUP_CONCAT(DISTINCTCONCAT('SUM(IF(quarter = ', quarter, ', amount, 0)) AS Q', quarter)) INTO @sqlFROM sales;-- 构建完整查询SET @sql = CONCAT('SELECT year, ', @sql, ', SUM(amount) AS Total FROM sales GROUP BY year');-- 准备并执行语句PREPARE stmt FROM @sql;EXECUTE stmt;DEALLOCATE PREPARE stmt;
END //DELIMITER ;-- 调用存储过程
CALL dynamic_pivot();

列转行(Unpivot)

列转行是将一行多列数据转换为多行数据的操作。

1. 使用 UNION ALL

这是最常用的列转行方法:

-- 示例数据(行转列后的结果)
CREATE TABLE sales_pivoted (year INT,Q1 DECIMAL(10,2),Q2 DECIMAL(10,2),Q3 DECIMAL(10,2),Q4 DECIMAL(10,2),Total DECIMAL(10,2)
);INSERT INTO sales_pivoted VALUES
(2020, 1000, 1500, 2000, 1800, 6300),
(2021, 1200, 1600, 2200, 1900, 6900);-- 列转行:将季度列转换为行
SELECT year, 1 AS quarter, Q1 AS amount FROM sales_pivoted
UNION ALL
SELECT year, 2 AS quarter, Q2 AS amount FROM sales_pivoted
UNION ALL
SELECT year, 3 AS quarter, Q3 AS amount FROM sales_pivoted
UNION ALL
SELECT year, 4 AS quarter, Q4 AS amount FROM sales_pivoted
ORDER BY year, quarter;

2. 使用 CROSS JOIN 和 VALUES(MySQL 8.0+)

MySQL 8.0 引入了 VALUES 语句,可以简化列转行操作:

-- 使用 VALUES 和 CROSS JOIN
SELECT s.year,v.quarter,CASE v.quarterWHEN 1 THEN s.Q1WHEN 2 THEN s.Q2WHEN 3 THEN s.Q3WHEN 4 THEN s.Q4END AS amount
FROM sales_pivoted s
CROSS JOIN (VALUES ROW(1),ROW(2),ROW(3),ROW(4)
) AS v(quarter)
ORDER BY s.year, v.quarter;

使用 JSON 函数进行行列转换(MySQL 5.7+)

MySQL 5.7 引入了 JSON 函数,可以用于更灵活的行列转换:

行转列使用 JSON

SELECT year,JSON_OBJECT('Q1', SUM(IF(quarter = 1, amount, 0)),'Q2', SUM(IF(quarter = 2, amount, 0)),'Q3', SUM(IF(quarter = 3, amount, 0)),'Q4', SUM(IF(quarter = 4, amount, 0))) AS quarterly_data
FROM sales
GROUP BY year;

列转行使用 JSON

SELECTyear,js.quarter,js.amount
FROM sales_pivoted,
JSON_TABLE(JSON_OBJECT('Q1', Q1,'Q2', Q2,'Q3', Q3,'Q4', Q4),'$.*' COLUMNS(quarter VARCHAR(10) PATH '$[0]',amount DECIMAL(10,2) PATH '$[1]')
) AS js;

总结

转换类型方法适用场景优点缺点
行转列CASE WHEN/IF + 聚合函数列名已知且固定简单直观,性能好列名固定,不够灵活
行转列动态SQL列名不固定灵活适应数据变化需要编写存储过程,较复杂
列转行UNION ALL任何MySQL版本简单通用代码冗长,性能随列数增加而下降
列转行CROSS JOIN + VALUESMySQL 8.0+代码简洁需要MySQL 8.0+
行列转换JSON函数MySQL 5.7+灵活处理复杂结构语法复杂,性能可能较差

在实际应用中,应根据数据特点、MySQL版本和性能要求选择合适的方法。对于简单的行列转换,CASE WHEN 和 UNION ALL 是最常用且兼容性最好的方法。对于更复杂或动态的需求,可以考虑使用动态SQL或JSON函数。

http://www.xdnf.cn/news/1361575.html

相关文章:

  • 在新塘SDK下面,有四中文件夹,GCC、IAR、KEIL、和Keil_AC6.这4个工程有什么区别。各自是怎样配置寄存器并实现SPI功能的
  • Aligning Effective Tokens with Video Anomaly in Large Language Models
  • Node.js面试题及详细答案120题(43-55) -- 性能优化与内存管理篇
  • 《飞算Java开发实战:从入门安装到项目部署》
  • 【GEE+Python 实战】用 Sentinel-2 监测 2024 年研究区 NDVI 变化(附完整源码与避坑指南)
  • Codejock Suite ProActiveX COM Crack
  • 一文掌握 Java 键盘输入:从入门到高阶(含完整示例与避坑指南)
  • LIANA | part1 intro部分
  • VMware Workstation 不可恢复错误:(vcpu-0)
  • 详细的周任务清单(Week1-Week24,每周具体目标+任务)
  • Socket some functions
  • 基于PHP服装租赁管理系统/基于php的服装管理系统的设计与实现
  • C#_gRPC
  • 【图像处理基石】基于 Python 的图像行人删除技术:实现街景无干扰化处理
  • 6.1Element UI布局容器
  • leetcode 162 寻找峰值
  • Polkadot - JAM
  • 13种常见机器学习算法总结
  • 青少年软件编程(python六级)等级考试试卷-客观题(2023年3月)
  • 学习制作记录(选项UI以及存档系统)8.24
  • 基于RISC-V架构的国产MCU在eVTOL领域的应用研究与挑战分析
  • 【Ollama】本地OCR
  • 波兰密码破译机bomba:二战密码战的隐形功臣
  • Shell 循环实战:while 与 until 的趣味编程之旅
  • 3.4 磁盘存储器 (答案见原书 P194)
  • 【重学MySQL】八十八、8.0版本核心新特性全解析
  • Unity的Cursor.lockState
  • DeepSeek对采用nginx实现透传以解决OpenShift 4.x 私有数据中心和公有云混合部署一套集群的解答
  • 【SBP】Unity 打包构建管线原理解析于对比
  • 联想win11笔记本音频失效,显示差号(x)