mysql实现列转行和行转列方式

 更新时间:2025年08月05日 10:03:52   作者:北风toto  
这篇文章主要介绍了mysql实现列转行和行转列方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

1、行转列(将多行数据转为单行多列)

1.1、使用 CASE WHEN + 聚合函数

SELECT 
    id,
    MAX(CASE WHEN subject = '数学' THEN score ELSE NULL END) AS '数学',
    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 id;

1.2、使用 IF + 聚合函数

SELECT 
    id,
    MAX(IF(subject = '数学', score, NULL)) AS '数学',
    MAX(IF(subject = '语文', score, NULL)) AS '语文',
    MAX(IF(subject = '英语', score, NULL)) AS '英语'
FROM student_scores
GROUP BY id;

1.3、使用 PIVOT (MySQL 8.0+)

SELECT 
    id,
    JSON_UNQUOTE(JSON_EXTRACT(pivot_data, '$.数学')) AS '数学',
    JSON_UNQUOTE(JSON_EXTRACT(pivot_data, '$.语文')) AS '语文',
    JSON_UNQUOTE(JSON_EXTRACT(pivot_data, '$.英语')) AS '英语'
FROM (
    SELECT 
        id,
        JSON_OBJECTAGG(subject, score) AS pivot_data
    FROM student_scores
    GROUP BY id
) AS t;

1.4、dataworks使用wm_concat函数和keyvalue

  • 缺点:当字符串存在英文冒号时会导致获取的值为空;中文冒号不受影响
  • 如果存在重复的数据,将导致取数时随机取其中一个;核心原因为wm_concat函数在拼接时顺序不固定,哪怕是增加了order by也没有用
  • keyvalue从字符串中取值时,如果有重复key,从左到右取第一个key的值
select  id
        ,keyvalue(column_value,'name') as name
        ,keyvalue(column_value,'age') as age
from    (
            select  id
                    ,wm_concat(';',concat(obj_name,':',obj_value)) as column_value
            from    school
            group by id
        ) 
;
-- 如果值存在英文冒号,导致取值为空的原因,看下面两个sql例子即可理解
-- 返回null
select keyvalue('name:小红:3737;age:13','name');
-- 返回3737
select keyvalue('name:小红:3737;age:13','name:小红');

2、列转行(将多列数据转为多行)

2.1、使用 UNION ALL

SELECT id, '数学' AS subject, 数学 AS score FROM student_scores_pivot
UNION ALL
SELECT id, '语文' AS subject, 语文 AS score FROM student_scores_pivot
UNION ALL
SELECT id, '英语' AS subject, 英语 AS score FROM student_scores_pivot
ORDER BY id, subject;

2.2、使用 CROSS JOIN + 条件筛选

  • 优点是不用频繁读取磁盘
SELECT 
    s.id,
    c.subject,
    CASE c.subject
        WHEN '数学' THEN s.数学
        WHEN '语文' THEN s.语文
        WHEN '英语' THEN s.英语
    END AS score
FROM student_scores_pivot s
CROSS JOIN (
    SELECT '数学' AS subject UNION ALL
    SELECT '语文' UNION ALL
    SELECT '英语'
) c;
  • 同样的语句,使用values和row
SELECT 
    s.id,
    c.subject,
    CASE c.subject
        WHEN '数学' THEN s.数学
        WHEN '语文' THEN s.语文
        WHEN '英语' THEN s.英语
    END AS score
FROM student_scores_pivot s
CROSS JOIN (
	values
    row('数学') 
    ,row('语文')
    ,row('英语')
) c(subject);

2.3、使用 JSON 函数 (MySQL 8.0+)

SELECT 
    id,
    jt.subject,
    jt.score
FROM student_scores_pivot,
JSON_TABLE(
    JSON_OBJECT(
        '数学', 数学,
        '语文', 语文,
        '英语', 英语
    ),
    '$.*' COLUMNS(
        subject VARCHAR(10) PATH '$.key',
        score INT PATH '$.value'
    )
) AS jt;

3、动态行转列

  • 对于不确定列名的情况,可以使用存储过程动态生成SQL:
DELIMITER //
CREATE PROCEDURE dynamic_pivot(IN table_name VARCHAR(100), IN row_id VARCHAR(100), IN pivot_col VARCHAR(100), IN value_col VARCHAR(100))
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE col_name VARCHAR(100);
    DECLARE col_list TEXT DEFAULT '';
    DECLARE cur CURSOR FOR 
        SELECT DISTINCT pivot_col FROM table_name;
    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 ', pivot_col, ' = ''', col_name, ''' THEN ', value_col, ' ELSE NULL END) AS `', col_name, '`');
    END LOOP;
    CLOSE cur;
    
    SET @sql = CONCAT('SELECT ', row_id, ', ', col_list, ' FROM ', table_name, ' GROUP BY ', row_id, ';');
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
END //
DELIMITER ;

-- 调用存储过程
CALL dynamic_pivot('student_scores', 'id', 'subject', 'score');

4、详细测试demo

4.1、dataworks使用wm_concat函数和keyvalue实现行转列

-- 创建表
create table if not exists school (
`id` string,
`obj_name` string,
`obj_value` string
);

-- 插入测试数据
insert into school
values 
('1','name','小明'),
('1','age','12'),
('2','name','小红'),
('2','age','13')
;


-- 列转行
select  id
        ,keyvalue(column_value,'name') as name
        ,keyvalue(column_value,'age') as age
from    (
            select  id
                    ,wm_concat(';',concat(obj_name,':',obj_value)) as column_value
            from    school
            group by id
        ) 
;

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • mysql sql字符串截取函数详解

    mysql sql字符串截取函数详解

    mysql支持的字符串截取函数主要有 left()、right()、substring()、substring_index(),下面是这些函数的详细使用方法
    2022-10-10
  • MySQL参数优化信息参考(my.cnf参数优化)

    MySQL参数优化信息参考(my.cnf参数优化)

    下面针对一些参数进行说明,当然还有其它的设置可以起作用,取决于你的负载或硬件:在慢内存和快磁盘、高并发和写密集型负载情况下,你将需要特殊的调整
    2024-07-07
  • MySQL连接异常报10061错误问题解决

    MySQL连接异常报10061错误问题解决

    这篇文章主要介绍了MySQL连接异常报10061错误问题解决,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • MySQL针对Discuz论坛程序的基本优化教程

    MySQL针对Discuz论坛程序的基本优化教程

    这篇文章主要介绍了MySQL针对Discuz论坛程序的基本优化教程,包括在缓存和索引等方面的优化方法,需要的朋友可以参考下
    2015-11-11
  • 安装mysql出错”A Windows service with the name MySQL already exists.“如何解决

    安装mysql出错”A Windows service with the name MySQL already exis

    这篇文章主要介绍了安装mysql出错”A Windows service with the name MySQL already exists.“如何解决的相关资料,在日常项目中此问题比较多见,特此把解决办法分享给大家,供大家参考
    2016-05-05
  • MySQL如何快速定位慢SQL的实战

    MySQL如何快速定位慢SQL的实战

    在项目中我们会经常遇到慢查询,当我们遇到慢查询的时候一般都要开启慢查询日志,本文主要介绍了MySQL如何快速定位慢SQL的实战,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • MySQL优化之如何写出高质量sql语句

    MySQL优化之如何写出高质量sql语句

    在数据库日常维护中,最常做的事情就是SQL语句优化,因为这个才是影响性能的最主要因素。这篇文章主要给大家介绍了关于MySQL优化之如何写出高质量sql语句的相关资料,需要的朋友可以参考下
    2021-05-05
  • MySQL数据库事务隔离级别介绍(Transaction Isolation Level)

    MySQL数据库事务隔离级别介绍(Transaction Isolation Level)

    这篇文章主要介绍了MySQL数据库事务隔离级别(Transaction Isolation Level) ,需要的朋友可以参考下
    2014-05-05
  • 升级到MySQL5.7后开发不得不注意的一些坑

    升级到MySQL5.7后开发不得不注意的一些坑

    这篇文章主要给大家介绍了关于升级到MySQL5.7后开发不得不注意的一些坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-07-07
  • mysql重装后出现乱码设置为utf8可解决

    mysql重装后出现乱码设置为utf8可解决

    mysql重装后出现乱码解决办法:只能在配置文件中将database 和 server 字符集 设置为utf8 ,否则不起作用,具体如下感兴趣的朋友可以参考下哈,希望对大家有所帮助
    2013-07-07

最新评论