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

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)

日记本

相关文章:

Apache Doris 行列转换可以这样玩

行列转换在做报表分析时还是经常会遇到的,今天就说一下如何实现行列转换吧。 行列转换就是如下图所示两种展示形式的互相转换 1. 行转列 我们来看一个简单的例子,我们要把下面这个表的数据,转换成图二的样式 image-20230914151818953.png …...

【Qt图形视图框架】自定义QGraphicsItem和QGraphicsView,实现鼠标(移动、缩放)及键盘事件、右键事件

自定义QGraphicsItem和QGraphicsView 说明示例myitem.hmyitem.cppmyview.hmyview.cpp调用main.cpp 效果 说明 在使用Qt的图形视图框架实现功能时,一般会在其基础上进行自定义功能实现。 如:滚轮对场景的缩放,鼠标拖动场景中的项,…...

C语言结构体指针学习

结构体变量存放内存中,也有起始地址,定义一个变量来存放这个地址,那这个变量就是结构体指针; typedef struct mydata{int a1;int a2;int a3; }mydata;void CJgtzzView::OnDraw(CDC* pDC) {CJgtzzDoc* pDoc GetDocument();ASSERT…...

华为云云耀云服务器L实例评测|部署在线轻量级备忘录 memos

华为云云耀云服务器L实例评测|部署在线轻量级备忘录 memos 一、云耀云服务器L实例介绍1.1 云服务器介绍1.2 产品优势1.3 应用场景1.4 支持镜像 二、云耀云服务器L实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 memos3.1 memos介绍3.2 Docker 环境搭建…...

详解Avast Driver Updater:电脑驱动更新工具的利器还是多余的软件?

亲爱的读者朋友们,你是不是经常为电脑的驱动问题而烦恼?如果是的话,你可能会对这款软件——Avast Driver Updater 电脑驱动更新工具感兴趣。但在你决定尝试之前,不妨先和我一起深入探讨一下它的优点、缺点以及它适用的使用场景。 …...

大数据Flink(九十五):DML:Window TopN

文章目录 DML:Window TopN DML:Window TopN Window TopN 定义(支持 Streaming):Window TopN 是一种特殊的 TopN,它的返回结果是每一个窗口内的 N 个最小值或者最大值。 应用场景...

使用OKHttpClient访问网络

使用OKHttpClient前要引入依赖: 在build.gradle(Moduel :app)中添加 implementation com.squareup.okhttp3:okhttp:3.14.1 implementation com.squareup.okhttp3:logging-interceptor:3.14.1 implementation com.squareup.okio:okio:1.6.0 1. GET(同步…...

maui 开发AMD CPU踩的坑。

刚换的 amd R7735HS 笔记本,8核16线程,32GB内存。性能得实强悍 。 当需要发布iOS版本时发现,我没有macos ,那就安装个vmware 吧。看了一下Apple 要求以后的发布的APP需要以xcode14.3或以后版本开发的版本,但xcode14.3…...

宝塔反代openai官方API接口详细教程,502 Bad Gateway问题解决

一、前言 宝塔反代openai官方API接口详细教程,实现国内使用ChatGPT502 Bad Gateway问题解决, 此方法最简单快捷,没有复杂步骤,不容易出错,即最简单,零代码、零部署的方法。 二、实现前提 一台海外VPS服务…...

【leetocde】128. 最长连续序列

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入:nums [100,4,200,1,3,2] 输出:4 …...

【Vue3】动态 class 类

如果你想在 Vue.js 中动态设置元素的 class 类名,你可以使用以下两种主要方式: 绑定一个动态的 class 对象:你可以使用 v-bind 或简写的 : 来绑定一个包含类名的对象,其中类名的键是类名字符串,值是一个布尔值或计算属…...

【Redis】redis基本数据类型详解(String、List、Hash、Set、ZSet)

目录 RedisString(字符串)List(列表)Hash(字典)Set(集合)ZSet(有序集合) Redis Redis有5种基本的数据结构,分别为:string(字符串)、list(列表)、set(集合)、hash(哈希&a…...

ubuntu源码安装aria2

github:GitHub - aria2/aria2: aria2 is a lightweight multi-protocol & multi-source, cross platform download utility operated in command-line. It supports HTTP/HTTPS, FTP, SFTP, BitTorrent and Metalink. 发行说明:GitHub - aria2/aria2 at releas…...

【多任务案例:猫狗脸部定位与分类】

【猫狗脸部定位与识别】 1 引言2 损失函数3 The Oxford-IIIT Pet Dataset数据集4 数据预处理4 创建模型输入5 自定义数据集加载方式6 显示一批次数据7 创建定位模型8 模型训练9 绘制损失曲线10 模型保存与预测 1 引言 猫狗脸部定位与识别分为定位和识别,即定位猫狗…...

.Net 锁的介绍

在.NET中,有多种锁机制可用于多线程编程,用来确保线程安全和共享资源的同步。以下是.NET中常见的锁机制: 1. **Monitor(互斥锁):** `Monitor` 是.NET中最基本的锁机制之一。它使用 `lock` 关键字实现,可以确保在同一时刻只有一个线程能够访问被锁定的代码块。`Monitor`…...

Office 2021 小型企业版商用办公软件评测:提升工作效率与协作能力的专业利器

作为一名软件评测人员,我将为您带来一篇关于 Office 2021 小型企业版商用办公软件的评测文章。在这篇评测中,我将从实用性、使用场景、优点和缺点等多个方面对该软件进行客观分析,在专业角度为您揭示它的真正实力和潜力。 一、实用性&#xf…...

Monkey测试

一:测试环境搭建 1:下载android-sdk_r24.4.1-windows 2:下载Java 3:配置环境变量:关于怎么配置环境变量(百度一下:monkey环境搭建,) 二:monkey测试&#xff1…...

wzx-jmw:NFL合理,但可能被颠覆。2023-2024

As well known by all, NFL is ... 没有免费的午餐理论 No Free Lunch Theorem_免费午餐理论-CSDN博客 However, if we......

密码技术 (5) - 数字签名

一. 前言 前面在介绍消息认证码时,我们知道消息认证码虽然可以确认消息的完整性,但是无法防止否认问题。而数字签名可以解决否认的问题,接下来介绍数字签名的原理。 二. 数字签名的原理 数字签名和公钥密码一样,也有公钥和私钥&am…...

php实战案例记录(10)单引号和双引号的用法和区别

在 PHP 中,单引号和双引号都被用于表示字符串。它们有一些共同之处,但也有一些明显的区别。 解析变量: 双引号允许解析变量,而单引号不会。在双引号中,你可以直接在字符串中插入变量,而不需要进行额外的连接…...

嵌入式Linux应用开发-基础知识-第十九章驱动程序基石②

嵌入式Linux应用开发-基础知识-第十九章驱动程序基石② 第十九章 驱动程序基石②19.3 异步通知19.3.1 适用场景19.3.2 使用流程19.3.3 驱动编程19.3.4 应用编程19.3.5 现场编程19.3.6 上机编程19.3.7 异步通知机制内核代码详解 19.4 阻塞与非阻塞19.4.1 应用编程19.4.2 驱动编程…...

trycatch、throw、throws

在Java中,try-catch、throw和throws是用于处理异常的重要关键字和机制,它们的作用如下: try-catch:try-catch 是用于捕获和处理异常的语句块。在try块中放置可能引发异常的代码。如果在try块中的代码引发了异常,控制流会跳转到与异常类型匹配的catch块。在catch块中,可以…...

问 ChatGPT 关于 GPT 的事情:数据准备篇

一、假如你是一名人工智能工程师,手里有一个65B的GPT大模型,但你需要一个6B左右的小模型,你会怎么做? 答:作为人工智能工程师,如果我手里有一个65B的GPT大模型,而我需要一个6B左右的小模型&…...

leetcode_17电话号码的组合

1. 题意 输出电话号码对应的字母左右组合 电话号码的组合 2. 题解 回溯 class Solution { public:void gen_res(vector<string> &res, vector<string> &s_m,string &digits, string &t, size_t depth) {if (depth digits.size()) {if ( !t.em…...

记录使用vue-test-utils + jest 在uniapp中进行单元测试

目录 前情安装依赖package.json配置jest配置测试文件目录编写setup.js编写第一个测试文件jest.fn()和jest.spyOn()jest 解析scss失败测试vuex$refs定时器测试函数调用n次手动调用生命周期处理其他模块导入的函数测试插槽 前情 uniapp推荐了测试方案dcloudio/uni-automator&…...

《C和指针》笔记30:函数声明数组参数、数组初始化方式和字符数组的初始化

文章目录 1. 函数声明数组参数2. 数组初始化方式2.1 静态初始化2.2 自动变量初始化 2.2 字符数组的初始化 1. 函数声明数组参数 下面两个函数原型是一样的&#xff1a; int strlen( char *string ); int strlen( char string[] );可以使用任何一种声明&#xff0c;但哪个“更…...

VBA技术资料MF64:遍历单元格搜索字符并高亮显示

【分享成果&#xff0c;随喜正能量】不要在乎他人的评论&#xff0c;不必理论与他人有关的是非&#xff0c;你只要做好自己就够了。苔花如米小&#xff0c;也学牡丹开。无论什么时候&#xff0c;都要有忠于自己的勇气&#xff0c;去做喜欢的事&#xff0c;去认识喜欢的人&#…...

一键智能视频编辑与视频修复算法——ProPainter源码解析与部署

前言 视频编辑和修复确实是随着电子产品的普及变得越来越重要的技能。有许多视频编辑工具可以帮助人们轻松完成这些任务如&#xff1a;Adobe Premiere Pro&#xff0c;Final Cut Pro X&#xff0c;Davinci Resolve&#xff0c;HitFilm Express&#xff0c;它们都提供一些视频修…...

Flutter开发环境的配置

2023-10最新版本 flutter SDK版本下载地址 https://flutter.cn/docs/development/tools/sdk/releases gradle各版本快速下载地址 https://blog.csdn.net/ii950606/article/details/109105402 JAVA SDK下载地址 https://www.oracle.com/java/technologies/downloads/#java…...

【超详细】Wireshark教程----Wireshark 分析ICMP报文数据试验

一&#xff0c;试验环境搭建 1-1 试验环境示例图 1-2 环境准备 两台kali主机&#xff08;虚拟机&#xff09; kali2022 192.168.220.129/24 kali2022 192.168.220.3/27 1-2-1 网关配置&#xff1a; 编辑-------- 虚拟网路编辑器 更改设置进来以后 &#xff0c;先选择N…...

甘肃兰州流感最新消息/南京百度seo代理

我们在内存里可以串起一棵树&#xff0c; 但是我们总得想办法保存下来。 比如机器要关了&#xff0c;内存里的东西都要销毁了&#xff0c; 我们需要怎么样才能将指针那些东西保存成文件的格式&#xff01;以便于我们下回重建出这棵树。 这就是本节要讲的 序列化和反序列化的问题…...

无锡高端网站建设公司哪家好/楚雄今日头条新闻

题意 题目链接 Sol 比较套路吧&#xff0c;设\(f[i][j]\)表示以\(i\)为根的子树中选了\(j\)个黑点对答案的贡献 然后考虑每条边的贡献&#xff0c;边的两边的答案都是可以算出来的 转移的时候背包一下。 #include<bits/stdc.h> #define Pair pair<int, int> #defin…...

公司微信网站制作/企业如何开展网络营销

---layout: posttitle: "linux ssd bug"date: 2019-09-30categories: hardware---# 1. bug 描述安装了 manjaro 的 xps 9350&#xff0c;睡眠长时间放电后&#xff0c;无法启动系统。现象&#xff1a;- 电脑可以正常启动 bios, 可以进入 grub, 选择 manjaro 后无法找…...

做外汇看新闻在什么网站看/开发小程序

这里是重点,<ripple>是API21才有的新Tag,正是实现水波纹效果的; 其中<ripple android:color"#FF21272B" .... />这个是指定水波纹的颜色. 而<item />里面的东西,我们都很熟悉,就是普通的定义一个带圆角的背景. ripple_bg.xml: <?xml version&q…...

东莞网站设计公司/搭建网站平台需要多少钱

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼说明&#xff1a;以下文件名及文件夹名均不区分大小写&#xff0c;而且所有字母和数字都是英文半角字符。(1)、建立名称为IT的文件夹&#xff0c;并在文件夹下建立如下文件夹结构&#xff1a;IT————打印机——扫描仪——数码相…...

视频网站是如何做的/会员制营销方案

2019独角兽企业重金招聘Python工程师标准>>> 1.ListView滑动方向判断 代码很简单&#xff0c;给mListView监听onScrollListener事件&#xff0c;然后在onScroll进行判断 //listView中第一项的索引private int mListViewFirstItem 0;//listView中第一项的在屏幕中的…...