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

MySQL 行转列 (Pivot) 的 N 种实现方式:静态、动态与 GROUP_CONCAT 详解

MySQL中的"行转列"是一个经典且非常实用的数据处理技巧,通常用于将数据从一种易于存储的格式转换为一种更易于阅读和报告的格式。下面我将详细解释其概念、方法和应用场景。

核心概念:什么是行转列?

-   **行数据**:通常指数据库中最自然的存储格式,每一行代表一条独立的记录。

| 学生姓名 | 科目 | 成绩 |

| :------- | :--- | :--- |

| 张三     | 语文 | 90   |

| 张三     | 数学 | 85   |

| 李四     | 语文 | 95   |

| 李四     | 数学 | 70   |

-   **列数据**(行转列后的目标):将某一列的唯一值(如`科目`)转换为新的列名,并将其对应的值(如`成绩`)填充到新列下。

| 学生姓名 | 语文 | 数学 |

| :------- | :--- | :--- |

| 张三     | 90   | 85   |

| 李四     | 95   | 70   |

这种转换也称为**数据透视(PIVOT)**。

---

### 实现行转列的几种方法

假设我们有上文的成绩表 `scores`。

方法一:使用 `CASE WHEN` + 聚合函数(最通用、最灵活)

这是最经典和兼容性最好的方法,适用于几乎所有版本的 MySQL。

**思路**:

1.  使用 `GROUP BY` 按唯一标识(如`学生姓名`)分组,确保一行一个学生。

2.  对每个需要转换的列值,使用 `CASE WHEN`(或 `IF`)语句判断并提取对应的值。

3.  使用 `MAX` 或 `MIN`、`SUM` 等聚合函数对提取出的值进行聚合(通常用于确保每个分组下只有一个非空值)。

**SQL 示例**:

```sql

SELECT

学生姓名,

MAX(CASE WHEN 科目 = '语文' THEN 成绩 ELSE NULL END) AS 语文,

MAX(CASE WHEN 科目 = '数学' THEN 成绩 ELSE NULL END) AS 数学

-- , ...可以继续添加其他科目

FROM scores

GROUP BY 学生姓名;

```

**结果**:

| 学生姓名 | 语文 | 数学 |

| :------- | :--- | :--- |

| 张三     | 90   | 85   |

| 李四     | 95   | 70   |

**为什么用 `MAX`?**

因为 `GROUP BY` 后,每个学生的每门科目理论上只有一条记录。`MAX` 的作用是取回那条唯一记录的值。如果不用聚合函数,SQL 会报错。你也可以用 `MIN` 或 `SUM`,效果相同。

方法二:使用 `IF()` + 聚合函数(MySQL 的简洁写法)

`IF(condition, value_if_true, value_if_false)` 是 `CASE WHEN` 的简化版,逻辑更清晰。

**SQL 示例**:

```sql

SELECT

学生姓名,

MAX(IF(科目 = '语文', 成绩, NULL)) AS 语文,

MAX(IF(科目 = '数学', 成绩, NULL)) AS 数学

FROM scores

GROUP BY 学生姓名;

```

效果与方法一完全相同。

方法三:使用 `GROUP_CONCAT`(另一种形式的“行转列”)

有时“转列”的目的不是生成多个新列,而是将多行数据**合并到一个单元格**中,用分隔符连接。这时 `GROUP_CONCAT` 非常有用。

**SQL 示例**:

```sql

SELECT

学生姓名,

GROUP_CONCAT(科目, ':', 成绩 SEPARATOR '; ') AS 成绩单

FROM scores

GROUP BY 学生姓名;

```

**结果**:

| 学生姓名 | 成绩单             |

| :------- | :----------------- |

| 张三     | 语文:90; 数学:85   |

| 李四     | 语文:95; 数学:70   |

---

高级应用:动态行转列

上面的方法有个巨大缺陷:**需要手动编写每个要转换的列值(如‘语文’、‘数学’)**。如果科目是不确定的(例如随时会增加‘英语’、‘物理’),上面的 SQL 就无法满足需求。

这时需要使用**存储过程(Stored Procedure)** 来**动态**生成 SQL 语句。

**思路**:

1.  查询出所有需要转换为列名的唯一值(如所有科目)。

2.  使用字符串拼接函数(如 `CONCAT`, `GROUP_CONCAT`)构造出包含所有 `CASE WHEN` 语句的 SQL 字符串。

3.  使用预处理语句(`PREPARE` & `EXECUTE`)来执行这个动态生成的 SQL 字符串。

**示例代码**:

```sql

-- 1. 定义变量存储动态生成的SQL

SET @sql = NULL;

-- 2. 查询所有不重复的科目,并拼接成 MAX(CASE WHEN...) 的格式

SELECT

GROUP_CONCAT(DISTINCT

CONCAT(

'MAX(IF(科目 = ''',

科目,

''', 成绩, NULL)) AS ',

CONCAT('`', 科目, '`') -- 用反引号包裹科目名,防止它是关键字

)

) INTO @sql

FROM scores;

-- 3. 拼接完整的SQL语句

SET @sql = CONCAT('SELECT 学生姓名, ', @sql, ' FROM scores GROUP BY 学生姓名');

-- 4. 预处理并执行动态SQL

PREPARE stmt FROM @sql;

EXECUTE stmt;

DEALLOCATE PREPARE stmt;

```

**执行结果**:无论科目如何变化,这段代码都会自动生成一个将所有科目作为列名的透视表。

| 学生姓名 | 语文 | 数学 | 英语 | (其他任何科目...) |

| :------- | :--- | :--- | :--- | :------------------ |

| 张三     | 90   | 85   | 92   | ...                 |

| 李四     | 95   | 70   | 88   | ...                 |

---

### 总结与选择

| 方法               | 适用场景                                       | 优点                         | 缺点                           |

| :----------------- | :--------------------------------------------- | :--------------------------- | :----------------------------- |

| **`CASE WHEN`/`IF`** | 要转换的列值是**固定的、已知的**(如科目固定) | 简单、直观、性能好           | 无法自动适应列值的变化         |

| **`GROUP_CONCAT`**  | 需要将多行数据合并到一个字段中显示             | 非常灵活,不会改变表结构     | 结果不是一个规整的二维表       |

| **动态SQL**        | 要转换的列值是**动态的、不确定的**(如科目可变) | 全自动,一劳永逸             | 编写复杂,需要用到存储过程和预处理 |

**核心要点**:

1.  **行转列的本质是条件判断和分组聚合**。

2.  静态转换使用 `CASE WHEN`/`IF` + `MAX` + `GROUP BY`。

3.  动态转换需要使用存储过程拼接 SQL,复杂度较高。

4.  在选择方法前,一定要明确需求中的“列”是否是固定的。

另外搭配便捷的MYSQL备份工具,可定时备份、异地备份,MYSQL导出导入。可本地连接LINUX里的MYSQL,简单便捷。可以大大地提高工作效率喔。

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

相关文章:

  • linux0.12 head.s代码解析
  • Langchain4j 整合MongoDB 实现会话持久化存储详解
  • Day34 UDP套接字编程 可靠文件传输与实时双向聊天系统
  • HTML5圣诞网站源码
  • Python基础(①①Ctypes)
  • Web安全——JWT
  • 厦门创客匠人靠谱嘛?从内容交付能力看其核心优势
  • el-tree 点击父节点无效,只能选中子节点
  • [BUUCTF-OGeek2019]babyrop详解(包含思考过程)
  • C++:类和对象(上)
  • 微软rStar2-Agent:新的GRPO-RoC算法让14B模型在复杂推理时超越了前沿大模型
  • 卷积操作原来分3种
  • 2025年工科生转型必考的十大高含金量证书!
  • 腾讯云建站多少钱?2025年最新价格曝光,0基础也能做出专业网站?实测真假
  • flutter专栏--深入剖析你的第一个flutter应用
  • 从一次Crash分析Chromium/360浏览器的悬空指针检测机制:raw_ref与BackupRefPtr揭秘
  • 留学第一天,语言不通怎么办?同声传译工具推荐来了
  • 常用假设检验方法及 Python 实现
  • 亚马逊云代理商:配置安全组规则步骤
  • kafka Partition(分区)详解
  • nestjs 阿里云服务端签名
  • 深度学习篇---SGD+Momentum优化器
  • Photoshop - Photoshop 触控手势
  • 电表连网不用跑现场!耐达讯自动化RS485转Profinet网关 远程配置+技术支持,真能做到!
  • ASP.NET 实战:用 SqlCommand 打造一个安全的用户注册功能
  • SIC8833芯片智能充气泵设计方案
  • 原创未发表!POD-PINN本征正交分解结合物理信息神经网络多变量回归预测模型,Matlab实现
  • 第二家公司虽然用PowerBI ,可能更适合用以前的QuickBI
  • pip completion工具作用(生成命令行自动补全脚本)(与pip-bash-completion区别)
  • 东土智建 | 让塔吊更聪明的“四大绝技”工地安全效率双升级