【列转行】(MySQL UNION / JSON_TABLE )

列转行(MySQL UNION / JSON_TABLE )

一、不同引擎实现方式说明

  1. MySQL:使用 UNION 语句合并多条查询结果,实现列转行
  2. JSON_TABLE 方法

第一题:列转行案例

原始数据表(学生各科成绩宽表)

表名:stu_score_wide

name english maths music
Jim 90 88 99

转换目标格式(窄表,一行一门成绩)

name subject score
Jim english 90
Jim maths 88
Jim music 99

解题思路

MySQL 方案:先单独提取每一门科目数据生成子结果,再通过 UNION ALL 合并所有结果集完成列转行

1. MySQL 测试建表与插入数据

sql 复制代码
CREATE TABLE stu_score (
    name VARCHAR(20) COMMENT '学生姓名',
    english INT COMMENT '英语成绩',
    maths INT COMMENT '数学成绩',
    music INT COMMENT '音乐成绩'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO stu_score(name, english, maths, music)
VALUES ('Jim', 90, 88, 99);
sql 复制代码
SELECT name, 'english' AS subject, english AS score FROM stu_score
UNION ALL
SELECT name, 'maths' AS subject, maths AS score FROM stu_score
UNION ALL
SELECT name, 'music' AS subject, music AS score FROM stu_score;

运行结果

MySQL JSON_TABLE 函数详解

函数说明

函数 作用 特点
JSON_TABLE() 将JSON数组/JSON对象,转换成多行数据表 MySQL8.0及以上新增,专门用于JSON数据行转列,替代复杂字符串截取逻辑

标准语法结构

sql 复制代码
JSON_TABLE(
    json源字符串,
    JSON路径表达式
    COLUMNS (
        输出列名 数据类型 PATH 'JSON字段路径'
    )
) 虚拟表别名

实战案例:电影多类型拆分列转行

数据表 Movie 电影表

movie category_list
看不见的客人 悬疑,动作,爱情
战狼 战争,动作,灾难
星际迷航 科幻,动作,剧情,灾难

建表与测试数据(MySQL)

sql 复制代码
CREATE TABLE Movie (
    movie VARCHAR(50) COMMENT '电影名称',
    category_list VARCHAR(100) COMMENT '逗号分隔的电影类型'
) COMMENT='电影类型表'
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO Movie(movie, category_list)
VALUES
('看不见的客人','悬疑,动作,爱情'),
('战狼','战争,动作,灾难'),
('星际迷航','科幻,动作,剧情,灾难');
sql 复制代码
SELECT
    movie,
    jt.category
FROM Movie,
JSON_TABLE(
    CONCAT('["', REPLACE(category_list, ',', '","'), '"]'),
    '$[*]' COLUMNS (category VARCHAR(20) PATH '$')
) jt;
  • 内层CONCAT+REPLACE把悬疑,动作,爱情转为 JSON 数组:"悬疑","动作","爱情"
    传入 JSON_TABLE 作为 JSON 数据源
  • $\*:遍历数组中每一个元素(悬疑、动作、爱情分别遍历)
  • COLUMNS (category VARCHAR(20) PATH '′)输出列名:category数据类型:VARCHAR(20)PATH′') 输出列名:category 数据类型:VARCHAR (20) PATH '′)输出列名:category数据类型:VARCHAR(20)PATH′':取当前遍历到的数组元素本身作为该列值
    最终生成一张名为jt的虚拟表,每行存放一个电影类型