当前位置: 首页 > 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.dtcms.com/a/349320.html

相关文章:

  • 堆栈面试题之有效的括号
  • 顶升机设计cad+三维图+设计说明书
  • AR智能巡检:重塑消防行业新未来
  • 【Axure高保真原型】嵌套表格_查看附件
  • AR智能巡检:智慧工地的高效安全新引擎
  • zookeeper-znode解析
  • 【P2P】P2P主要技术及RELAY服务实现
  • 前端 Promise 全面深入解析
  • Unity中的特殊文件夹
  • 【Python】在 Pydantic 模型中使用非 Pydantic 定义的类作为模型字段类型
  • Java项目-苍穹外卖_Day2
  • 8 设计URL短链
  • rust语言 (1.88) egui (0.32.1) 学习笔记(逐行注释)(二十) 文件、文件夹选择框、保存文件框
  • qt配置ros2环境,简单版本
  • Rust:变量、常量与数据类型
  • 2025 突出的时序模型
  • 【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day13
  • Linux-Redis的安装
  • 第四章:并发编程的基石与高级模式之Select语句与多路复用
  • 【Linux】开发工具命令指南:深度解析Vim的使用操作
  • Allegro17.4导出带有NET的PDF文档及组装样式图
  • MongoDB vs MySQL:NoSQL 和 SQL 的核心区别与适用场景
  • 前端开发:详细介绍npm、pnpm和cnpm分别是什么,使用方法以及之间有哪些关系
  • CPTS-Pressed复现(XML-RPC)
  • Python 面向对象进阶:深入理解封装、继承与多态
  • 【C++】第二十六节—C++11(中) | 右值引用和移动语义(续集)+lambda
  • 验证码流程
  • 【AMBA总线互联IP】
  • 6、RocketMQ消息积压问题如何解决
  • QSpinBox的用法及其使用QSS对其美化