SQL行列转置以及非常规的行列转置示例代码

 更新时间:2024年08月17日 10:22:53   作者:yangjiwei0207  
转置即旋转数据表的横纵方向,常用来改变数据布局,以便用新的角度观察,下面这篇文章主要给大家介绍了关于SQL行列转置以及非常规行列转置的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、准备工作

# 创建数据表
CREATE TABLE ChengJi
(
    Name    varchar(32),
    Subject varchar(32),
    Result  int(10)
);

# 插入数据
insert into ChengJi
values ('张三', '语文', 80),
       ('张三', '数学', 90),
       ('张三', '物理', 85),
       ('李四', '语文', 85),
       ('李四', '数学', 92),
       ('李四', '物理', 82);

二、行转列

整体分两步走

1、先预处理数据,将数据进行初步的行转列,便于后续的分组处理

select Name,
       case
            when Subject = '语文' then Result else 0
       end as 'Chinese',
       case
           when Subject = '数学' then Result else 0
       end as 'Math',
       case
           when Subject = '物理' then Result else 0
       end as 'Pha'
from ChengJi;

2、对预处理完毕的数据进行分组聚合,使多行数据汇聚到一个组内,达到数据集中的结果,这其中要注意的一点是:要明确按照哪个字段进行聚合操作。

with t1 as(select Name,
       case
            when Subject = '语文' then Result else 0
       end as 'Chinese',
       case
           when Subject = '数学' then Result else 0
       end as 'Math',
       case
           when Subject = '物理' then Result else 0
       end as 'Pha'
from ChengJi)
select Name,
       sum(Chinese) as 'Chinese',
       sum(Math) as 'Math',
       sum(Pha) as 'Pha'
from t1
group by Name;

三、列转行

为便于理解,我们将刚才已经转置好的结果插入到一个结果表内

1、创建一个结果表

create table ChengJi_2(
    Name varchar(255),
    Chinese int,
    Math int,
    Pha int
);

2、将行转列结果插入到结果表

insert into chengji_2
with t1 as(select Name,
       case
            when Subject = '语文' then Result else 0
       end as 'Chinese',
       case
           when Subject = '数学' then Result else 0
       end as 'Math',
       case
           when Subject = '物理' then Result else 0
       end as 'Pha'
from ChengJi)
select Name,
       sum(Chinese) as 'Chinese',
       sum(Math) as 'Math',
       sum(Pha) as 'Pha'
from t1
group by Name
;

3、对结果表进行列转行的操作,列转行相对于行转列较为简单,可直接使用 union all 进行操作。

select Name,Chinese from ChengJi_2
union all
select Name,Math from ChengJi_2
union all
select Name,Pha from ChengJi_2;

四、特殊的列转行/行转列

但是对于一些特殊的行列转置,以上方法就不再使用,通常情况下,我们的行列转置是有可以进行分组聚合操作可以完成的,而生产实践中也多数如此,但是有时有一些特殊的操作是以上方法无法完成的,这就需要一些特殊的行列转置来完成,对此,我给出了以下的方案。

1、准备工作,创建数据表并插入数据

CREATE TABLE 2003a
(
    seat   varchar(255) ,
    status varchar(255) ,
    rowid  varchar(255)
)
;

INSERT INTO 2003a
VALUES ('2', '已预订', 'A');
INSERT INTO 2003a
VALUES ('3', '未预订', 'A');
INSERT INTO 2003a
VALUES ('4', '未预订', 'A');
INSERT INTO 2003a
VALUES ('5', '未预订', 'A');
INSERT INTO 2003a
VALUES ('6', '未预订', 'B');
INSERT INTO 2003a
VALUES ('7', '未预订', 'B');
INSERT INTO 2003a
VALUES ('8', '未预订', 'B');
INSERT INTO 2003a
VALUES ('9', '未预订', 'B');
INSERT INTO 2003a
VALUES ('10', '未预订', 'B');
INSERT INTO 2003a
VALUES ('11', '未预订', 'C');
INSERT INTO 2003a
VALUES ('12', '已预订', 'C');
INSERT INTO 2003a
VALUES ('13', '已预订', 'C');
INSERT INTO 2003a
VALUES ('14', '未预订', 'C');
INSERT INTO 2003a
VALUES ('15', '未预订', 'C');
INSERT INTO 2003a
VALUES ('16', '未预订', 'D');
INSERT INTO 2003a
VALUES ('17', '未预订', 'D');
INSERT INTO 2003a
VALUES ('18', '未预订', 'D');
INSERT INTO 2003a
VALUES ('19', '未预订', 'D');
INSERT INTO 2003a
VALUES ('20', '已预订', 'D');

2、明确需求

原有表的结构:

2,已预订,A
3,未预订,A

需要完成的工作:

2,3
已预定,未预定
A,A

在这里我们可以很明显的看出,我们需要做的就是如何进行 行转列/列转行 的操作,在这里的行列转置是整行/整列进行转置,不再是依靠某个字段进行分组处理或者使用 union all 进行整体操作,因此,我是用以下方案来完成。

1、对原表字段进行 group_concat,指定 “,”为字段值之间的分隔符

SELECT
                GROUP_CONCAT(rowid ORDER BY rowid ASC SEPARATOR ', ') AS rowid,
                GROUP_CONCAT(status ORDER BY rowid ASC SEPARATOR ', ') AS status,
                GROUP_CONCAT(seat ORDER BY rowid ASC SEPARATOR ', ') AS seat
            FROM (
                     SELECT rowid, status, seat from `2003a`
                 ) AS subquery

2、将所有的字段按照值聚合到一个数据表格内之后,我们可以使用 union all 来进行字段拆分

with t1 as (SELECT
                GROUP_CONCAT(rowid ORDER BY rowid ASC SEPARATOR ', ') AS rowid,
                GROUP_CONCAT(status ORDER BY rowid ASC SEPARATOR ', ') AS status,
                GROUP_CONCAT(seat ORDER BY rowid ASC SEPARATOR ', ') AS seat
            FROM (
                     SELECT rowid, status, seat from `2003a`
                 ) AS subquery)
select seat from t1
union all
select status from t1
union all
select rowid from t1

3、使用 SUBSTRING_INDEX来进行拆分,将所有的字段值拆分成单独的值

with t1 as (SELECT
                GROUP_CONCAT(rowid ORDER BY rowid ASC SEPARATOR ', ') AS rowid,
                GROUP_CONCAT(status ORDER BY rowid ASC SEPARATOR ', ') AS status,
                GROUP_CONCAT(seat ORDER BY rowid ASC SEPARATOR ', ') AS seat
            FROM (
                     SELECT rowid, status, seat from `2003a`
                 ) AS subquery)
,t2 as (select seat from t1
union all
select status from t1
union all
select rowid from t1)
select SUBSTRING_INDEX(seat,',',1) as p1,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',2),',',-1) as p2,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',3),',',-1) as p3,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',4),',',-1) as p4,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',5),',',-1) as p5,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',6),',',-1) as p6,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',7),',',-1) as p7,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',8),',',-1) as p8,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',9),',',-1) as p9,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',10),',',-1) as p10,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',11),',',-1) as p11,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',12),',',-1) as p12,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',13),',',-1) as p13,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',14),',',-1) as p14,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',15),',',-1) as p15,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',16),',',-1) as p16,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',17),',',-1) as p17,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',18),',',-1) as p18,
       SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',19),',',-1) as p19
from t2

在这里需要注意的是:第一个SUBSTRING_INDEX我们取的是源数据的第一个值,第二个SUBSTRING_INDEX以及之后的,我们取得是源数据的倒数第一个值,因此这里需要注意一下我们给到的是“-1”

至此,我们使用group_concat()以及SUBSTRING_INDEX()来达到了特殊的行列转置操作。

总结 

到此这篇关于SQL行列转置以及非常规的行列转置的文章就介绍到这了,更多相关SQL行列转置内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • mysql InnoDB建表时设定初始大小的方法

    mysql InnoDB建表时设定初始大小的方法

    这篇文章主要介绍了mysql InnoDB建表时设定初始大小的方法,需要大家到MYSQL后台实际操作方可以看到效果
    2013-11-11
  • LEFT JOIN关联表中ON,WHERE后面跟条件的区别

    LEFT JOIN关联表中ON,WHERE后面跟条件的区别

    本文主要介绍了LEFT JOIN关联表中ON,WHERE后面跟条件的区别,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • sql获得当前时间以及SQL比较时间大小详解

    sql获得当前时间以及SQL比较时间大小详解

    最近写项目的时候功能需要在sql语句中获取当前时间,所以下面这篇文章主要给大家介绍了关于sql获得当前时间以及SQL比较时间大小的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-04-04
  • mysql基础架构教程之查询语句执行的流程详解

    mysql基础架构教程之查询语句执行的流程详解

    这篇文章主要给大家介绍了关于mysql基础架构教程之查询语句执行流程的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧
    2018-11-11
  • Navicat操作MYSQL的详细过程

    Navicat操作MYSQL的详细过程

    这篇文章主要介绍了Navicat操作MYSQL的详细过程,包括数据表的操作修改删除操作,本文给大家介绍的非常详细,需要的朋友可以参考下
    2024-03-03
  • mysql ERROR 1045 (28000)问题的解决方法

    mysql ERROR 1045 (28000)问题的解决方法

    这篇文章主要介绍了mysql ERROR 1045 (28000)问题的解决方法,文中步骤介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • Mysql 删除数据库drop database详细介绍

    Mysql 删除数据库drop database详细介绍

    在mysql中,我们可以使用DROP DATABASE来删除数据库,并且数据库中所有表也随之删除。本文通过实例向各位码农介绍DROP DATABASE的使用方法,需要的朋友可以参考下
    2016-11-11
  • mysql配置连接参数设置及性能优化

    mysql配置连接参数设置及性能优化

    这篇文章主要介绍了mysql配置连接参数设置及性能优化,主要介绍配置信息的说明和性能优化,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-05-05
  • Mysql提升大数据表拷贝效率的解决方案

    Mysql提升大数据表拷贝效率的解决方案

    这篇文章主要给大家介绍了关于Mysql提升大数据表拷贝效率的解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-09-09
  • 图解Mysql中的LEFT JOIN、RIGHT JOIN与JOIN的区别

    图解Mysql中的LEFT JOIN、RIGHT JOIN与JOIN的区别

    这篇文章主要介绍了图解Mysql中的LEFT JOIN、RIGHT JOIN与JOIN的区别,Left Join就是以左边为基准,Inner Join就是查两个重复的部分,Right Join就是以右边为基准,需要的朋友可以参考下
    2023-11-11

最新评论