Apache Doris 行列转换可以这样玩

行列转换在做报表分析时还是经常会遇到的,今天就说一下如何实现行列转换吧。

行列转换就是如下图所示两种展示形式的互相转换

1. 行转列

我们来看一个简单的例子,我们要把下面这个表的数据,转换成图二的样式

image-20230914151818953.png

要转换的结果数据展示

image-20230914152642915.png

先看看建表语句:

CREATE TABLE tb_score_01(id INT(11) NOT NULL,userid VARCHAR(20) NOT NULL COMMENT '用户id',subject VARCHAR(20) COMMENT '科目',score DOUBLE COMMENT '成绩'
)
DUPLICATE KEY(`id`)
COMMENT 'OLAP'
DISTRIBUTED BY HASH(`id`) BUCKETS 1
PROPERTIES (
"replication_allocation" = "tag.location.default: 1",
"in_memory" = "false",
"storage_format" = "V2",
"light_schema_change" = "true",
"disable_auto_compaction" = "false"
);INSERT INTO tb_score_01  VALUES (1,'001','语文',90);
INSERT INTO tb_score_01  VALUES (2,'001','数学',92);
INSERT INTO tb_score_01  VALUES (3,'001','英语',80);
INSERT INTO tb_score_01  VALUES (4,'002','语文',88);
INSERT INTO tb_score_01  VALUES (5,'002','数学',90);
INSERT INTO tb_score_01  VALUES (6,'002','英语',75.5);
INSERT INTO tb_score_01  VALUES (7,'003','语文',70);
INSERT INTO tb_score_01  VALUES (8,'003','数学',85);
INSERT INTO tb_score_01  VALUES (9,'003','英语',90);
INSERT INTO tb_score_01  VALUES (10,'003','政治',82);

传统的做法我们大概是这样实现,一般是通过 case when 语句

SELECT userid,
SUM(CASE `subject` WHEN '语文' THEN score ELSE 0 END) as '语文',
SUM(CASE `subject` WHEN '数学' THEN score ELSE 0 END) as '数学',
SUM(CASE `subject` WHEN '英语' THEN score ELSE 0 END) as '英语',
SUM(CASE `subject` WHEN '政治' THEN score ELSE 0 END) as '政治' 
FROM tb_score 
GROUP BY userid;或者SELECT userid,
SUM(IF(`subject`='语文',score,0)) as '语文',
SUM(IF(`subject`='数学',score,0)) as '数学',
SUM(IF(`subject`='英语',score,0)) as '英语',
SUM(IF(`subject`='政治',score,0)) as '政治' 
FROM tb_score 
GROUP BY userid;

我们来看看 Doris 怎么实现这个行转列呢,有没有更简单、性能更好的一种方式

  1. 我们是不是可以首先将这个科目、成绩组成一个Map

  2. 然后在外层对这个 Map 进行遍历展开

  3. 从而完成这样一个行列转换呢

我们来看看实现

select userid,IFNULL(map['语文'],0) as '语文',IFNULL(map['英语'],0) as '英语',IFNULL(map['数学'],0) as '数学',IFNULL(map['政治'],0) as '政治'
from  (select userid ,map_agg(subject,score) as map from tb_score group by userid
) t ;

这样实现上性能更好,我们来看一下效果

select->     userid,->     IFNULL(map['语文'],0) as '语文',->     IFNULL(map['英语'],0) as '英语',->     IFNULL(map['数学'],0) as '数学',->     IFNULL(map['政治'],0) as '政治'-> from  (->     select userid ,map_agg(subject,score) as map from tb_score group by userid-> ) t ;
+--------+--------+--------+--------+--------+
| userid | 语文   | 英语   | 数学   | 政治   |
+--------+--------+--------+--------+--------+
| 001    |     90 |     80 |     92 |      0 |
| 002    |     88 |   75.5 |     90 |      0 |
| 003    |     70 |     90 |     85 |     82 |
+--------+--------+--------+--------+--------+
3 rows in set (0.02 sec)

2. 列转行

实际使用中我们还有很多场景要把数据冲列转成行,下面我们来看一个例子,这个例子中每行是一个学生的,语文、数学、英语、政治的成绩,

image-20230914152642915.png

我们想转换成每门成绩都是独立的一行,转出的效果如下:

image-20230914152846996.png

我们来看看一个宽表转成高表我们之前的是怎么实现,一般我们是通过union all的方式,每科我们都是一个单独的SQL语句,然后将这些SQL Unoin all 在一起得到我们想要的结果。

SELECT userid,'语文' AS course,cn_score AS score FROM tb_score1
UNION ALL
SELECT userid,'数学' AS course,math_score AS score FROM tb_score1
UNION ALL
SELECT userid,'英语' AS course,en_score AS score FROM tb_score1
UNION ALL
SELECT userid,'政治' AS course,po_score AS score FROM tb_score1
ORDER BY userid;

这样做的缺点:

  1. SQL 冗余

  2. 大量的union all 也会带来性能问题

我们来看看 Doris 怎么实现,首先 Doris 提供了 Lateral view,其实就是用来和像类似explode这种UDTF函数联用的,lateral view会将 UDTF 生成的结果放到一个虚拟表中,然后这个虚拟表会和输入行进行 join来达到连接 UDTF 外的 select 字段的目的

还是以上面的例子来看,Doris我怎么对这个宽表转成高表,实现就是借助Lateral view

CREATE TABLE `tb_score1` (`id` int(11) NOT NULL,`userid` varchar(20) NOT NULL COMMENT '用户id',`cn_score` double NULL COMMENT '语文成绩',`math_score` double NULL COMMENT '数学成绩',`en_score` double NULL COMMENT '英语成绩',`po_score` double NULL COMMENT '政治成绩'
) ENGINE=OLAP
UNIQUE KEY(`id`)
COMMENT 'OLAP'
DISTRIBUTED BY HASH(`id`) BUCKETS 1
PROPERTIES (
"replication_allocation" = "tag.location.default: 1",
"is_being_synced" = "false",
"storage_format" = "V2",
"light_schema_change" = "true",
"disable_auto_compaction" = "false",
"enable_single_replica_compaction" = "false"
);;INSERT INTO `tb_score1` (`id`, `userid`, `cn_score`, `math_score`, `en_score`, `po_score`) VALUES (1, '001', 90, 92, 80, 0);
INSERT INTO `tb_score1` (`id`, `userid`, `cn_score`, `math_score`, `en_score`, `po_score`) VALUES (2, '002', 88, 90, 75.5, 0);
INSERT INTO `tb_score1` (`id`, `userid`, `cn_score`, `math_score`, `en_score`, `po_score`) VALUES (3, '003', 70, 85, 90, 82);
  1. 首先我借助Lateral view 形成一个 UserID、客户成绩组成一个字符(使用逗号连接),达到下面的效果
+--------+--------------------+
| userid | arr                |
+--------+--------------------+
| 001    | ["语文", "90"]     |
| 001    | ["数学", "92"]     |
| 001    | ["英语", "80"]     |
| 001    | ["政治", "0"]      |
| 002    | ["语文", "88"]     |
| 002    | ["数学", "90"]     |
| 002    | ["英语", "75.5"]   |
| 002    | ["政治", "0"]      |
| 003    | ["语文", "70"]     |
| 003    | ["数学", "85"]     |
| 003    | ["英语", "90"]     |
| 003    | ["政治", "82"]     |
+--------+--------------------+
12 rows in set (0.02 sec)
  1. 然后对这个上面的 arr 字符串,借助于 Doris 提供的 SPLIT_BY_STRING 函数完成字符串转数组的动作

  2. 最后遍历数组

  3. 完成列转行的效果

SELECTuserid,element_at ( arr, 1 ) AS SUBJECT,element_at ( arr, 2 ) AS score 
FROM(SELECTuserid,SPLIT_BY_STRING ( sub, ',' ) arr FROM(SELECTuserid,array (concat( '语文', ',', cn_score ),concat( '数学', ',', math_score ),concat( '英语', ',', en_score ),concat( '政治', ',', po_score )) AS scores FROMtb_score1 ) t LATERAL VIEW explode ( scores ) tbl1 AS sub ) aaa

最后的效果如下:

SELECT->         userid,->         element_at ( arr, 1 ) AS SUBJECT,->         element_at ( arr, 2 ) AS score-> FROM->         (->         SELECT->                 userid,->                 SPLIT_BY_STRING ( sub, ',' ) arr->         FROM->                 (->                 SELECT->                         userid,->                         array (->                                 concat( '语文', ',', cn_score ),->                                 concat( '数学', ',', math_score ),->                                 concat( '英语', ',', en_score ),->                         concat( '政治', ',', po_score )) AS scores->                 FROM->                         tb_score1->                 ) t LATERAL VIEW explode ( scores ) tbl1 AS sub->         ) aaa;
+--------+---------+-------+
| userid | SUBJECT | score |
+--------+---------+-------+
| 001    | 语文    | 90    |
| 001    | 数学    | 92    |
| 001    | 英语    | 80    |
| 001    | 政治    | 0     |
| 002    | 语文    | 88    |
| 002    | 数学    | 90    |
| 002    | 英语    | 75.5  |
| 002    | 政治    | 0     |
| 003    | 语文    | 70    |
| 003    | 数学    | 85    |
| 003    | 英语    | 90    |
| 003    | 政治    | 82    |
+--------+---------+-------+
12 rows in set (0.02 sec)

日记本

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/88268.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

负载均衡器监控

什么是负载均衡器 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企…

[React] 自定义hooks设计模式

文章目录 1.自定义hooks设计1.1 自定义hooks1.2 设计一个自定义hooks1.3 自定义hooks的驱动条件1.4 自定义hooks的通用模式1.5 自定义hooks的条件限定 1.自定义hooks设计 react-hooks是react16.8以后,react新增的钩子API,目的是增加代码的可复用性&…

小程序为什么必须使用SSL证书?

随着互联网技术的发展,越来越多的网站和应用程序开始使用SSL证书来保护用户数据的安全。微信小程序作为一款广受欢迎的应用程序,也必须使用SSL证书来确保用户数据的安全。 首先,使用SSL证书可以保护用户数据的安全。SSL证书是一种数字证书&am…

玩转Mysql系列 - 第22篇:mysql索引原理详解

这是Mysql系列第22篇。 背景 使用mysql最多的就是查询,我们迫切的希望mysql能查询的更快一些,我们经常用到的查询有: 按照id查询唯一一条记录 按照某些个字段查询对应的记录 查找某个范围的所有记录(between and) …

5+单细胞+脂质代谢+预后模型+实验

今天给同学们分享一篇5单细胞脂质代谢预后模型实验的生信文章“Single-cell transcriptome analysis reveals the metabolic changes and the prognostic value of malignant hepatocyte subpopulations and predict new therapeutic agents for hepatocellular carcinoma”&am…

uniapp ui安装 阿里图标库使用 报错 Assignment to constant variable.

安装 ui uni-app官网 (dcloud.net.cn) (一)安装 pages.js配置 安装 sassnpm i sass -D 或 yarn add sass -D 安装 sass-loader npm i sass-loader10.1.1 -D 或 yarn add sass-loader10.1.1 -D安装 uni-uinpm i dcloudio/uni-ui 或 yarn a…

【开发篇】八、SpringBoot整合MongoBD

文章目录 1、整合2、简单示例3、一点思考4、MongoDB的安装5、MongoDB的CRUD语法 1、整合 导入MongoBD的起步依赖:(这个starter背后是MongoDB的驱动和其他依赖,在这儿也可以看出命名的规律,redis的就是spring-boot-starter-data-r…

(Mysql高级语句(进阶查询语句+数据库函数+连接查询))

Mysql高级语句(进阶查询语句MySQL数据库函数连接查询) 一、mysql查询语句1.1、 select ----显示表格中一个或数个字段的所有数据记录1.2、 distinct ----不显示重复的数据记录1.3、where ----有条件查询1.4、 and or ----且 或1.5 、in----显示已知的值的…

算法竞赛备赛之动态规划训练提升,DP基础掌握

1.背包问题 1.1.01背包问题 01背包问题是在M件物品中选择若干件放在空间为W的背包中,每件物品的体积为W1,W2至Wn,价值为P1,P2至Pn,01背包的约束条件是给定几种物品,每种物品有且只有一个,并且…

ChatGPT重磅升级:可以看图、听声音、说话啦!

美东时间9月25日,OpenAI在官网宣布,对ChatGPT进行重磅升级实现看图、听声音、输出语音内容三大功能。 早在今年3月OpenAI发布GPT-4模型时,就展示过看图的功能,但由于安全、功能不完善等原因一直没有开放。现在不仅开放了看图&…

TensorFlow入门(四、数据流向机制)

session与"图"工作过程中存在的两种数据的流向机制,即:注入机制和取回机制 注入机制(feed):即通过占位符向模式中传入数据 取回机制(fetch):指在执行计算图时,可以同时获取多个操作节点的计算结果 实例代码如下: import tensorflow.compat.v1 as tftf…

傅一平:2023年我的私人书单(上)

2023年一直在通过ChatGPT学习,读书少了,但不能不读。 这里推荐上半年读过的TOP 9 书单,同时附上我的一句话评语和豆瓣的评分,涉及思考方法、系统架构、跨学科知识、沟通技巧、生活感悟、个人修养等等。 TOP 1 佛畏系统-用系统思维…

解决apscheduler意外跳过任务【Execution of job “xx“(trigger:xxx), next run at: xxx】

解决方法 添加配置: max_instances:添加最多可同时进行的数量 misfire_grace_time:如果意外断开,多少秒以内会重新尝试运行 如: scheduler.add_job(print_each_5_second, interval, seconds5, max_instances10, mi…

Vue中的自定义指令详解

文章目录 自定义指令自定义指令-指令的值(给自定义指令传参数)自定义指令- v-loading指令封装 自定义指令 自定义指令:自己定义的指令,可以封装一些dom 操作,扩展额外功能(自动聚焦,自动加载&a…

HTML5+CSS3小实例:脉冲波纹催眠动画特效

实例:脉冲波纹催眠动画特效 技术栈:HTML+CSS 效果: 源码: 【html】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" content=&qu…

800G时代来临,千兆光模块万兆光模块还有用吗?

随着科技的不断进步&#xff0c;网络传输速度的需求也越来越高&#xff0c;特别是在云计算、人工智能、物联网等领域&#xff0c;对网络传输速度的要求越来越高。近年来&#xff0c;千兆光模块和万兆光模块已经成为了网络传输的主要手段&#xff0c;但随着800G时代的到来&#…

自学视觉SLAM(1)

引言 小编研究生的研究方向是视觉SLAM&#xff0c;目前在自学&#xff0c;已经学了Linux系统的基本操作&#xff0c;vim编辑器以及高翔老师的一些视屏。本篇文章为初学笔记。 文章目录 引言1 熟悉 Linux1.1 如何在 Ubuntu 中安装软件&#xff08;命令⾏界⾯&#xff09;&#x…

Python爬虫之入门保姆级教程

目录 一、分析要爬取的网站 二、导入相关库 三、相关的参数 四、向网站发出请求&#xff08;使用代理IP&#xff09; 五、匹配 六、获取图片&#xff0c;保存到文件夹中&#xff08;os库&#xff09; 七、完整代码 总结 相信许多人都曾为如何入门Python爬虫而烦恼。今天…

FastChat 大模型部署推理;Baichuan2-13B-Chat测试、chatglm2-6b测试

参考&#xff1a; https://github.com/lm-sys/FastChat https://blog.csdn.net/qq128252/article/details/132759107 ##安装 pip3 install "fschat[model_worker,webui]"模型下载&#xff1a; ##模型下载&#xff1b;huggingface下载慢&#xff0c;可以在modelscop…

安防视频平台EasyCVR视频调阅全屏播放显示异常是什么原因?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…