关于优雅的使用SQL多行转多列的记录(doris)

文章目录

  • 应用需求场景
  • 记录过程
      • [1. 准备数据](#1. 准备数据)
      • [2. 给数据根据姓名分组,加上序号.](#2. 给数据根据姓名分组,加上序号.)
      • [3. 根据name分组成map结构](#3. 根据name分组成map结构)
      • [4. 拆分map](#4. 拆分map)

应用需求场景

准备的数据是这样的:

需要将每个人的成绩显示在一行上,需要的结果如下,但是我的情况是课程有非常多,但不是每个课程都存在。我只想把这个人学习的3个课程列出来,所以这类有个问题,就是每个同学的课程不一定是语文、数学、英语,但是最大不多于3门课。

最终的结果如下:

记录过程

1. 准备数据

sql 复制代码
with tmp_a as (
	select 'a' name,'语文' clazz, 80 as score
	union all
	select 'a' name,'高数' clazz, 85 as score
	union all
	select 'a' name,'英语' clazz, 20 as score
	union all
	select 'b' name,'微积分' clazz, 70 as score
	union all
	select 'b' name,'数学' clazz, 75 as score
	union all
	select 'b' name,'现代' clazz, 71 as score
	union all
	select 'c' name,'物理' clazz, 70 as score
	union all
	select 'c' name,'音乐' clazz, 75 as score
	union all
	select 'c' name,'体育' clazz, 71 as score
)
select * from tmp_a;

2. 给数据根据姓名分组,加上序号.

sql 复制代码
with tmp_a as (
	select 'a' name,'语文' clazz, 80 as score
	union all
	select 'a' name,'高数' clazz, 85 as score
	union all
	select 'a' name,'英语' clazz, 20 as score
	union all
	select 'b' name,'微积分' clazz, 70 as score
	union all
	select 'b' name,'数学' clazz, 75 as score
	union all
	select 'b' name,'现代' clazz, 71 as score
	union all
	select 'c' name,'物理' clazz, 70 as score
	union all
	select 'c' name,'音乐' clazz, 75 as score
	union all
	select 'c' name,'体育' clazz, 71 as score
)
select *,row_number() over(partition by name order by clazz) rk
from tmp_a;

3. 根据name分组成map结构

注意:这里用到的map_agg是doris里面的,其他数据库不确定有没有。

map_agg(key,value) 这样使用的,这里将序号作为key,后面方便统一取值。

sql 复制代码
with tmp_a as (
	select 'a' name,'语文' clazz, 80 as score
	union all
	select 'a' name,'高数' clazz, 85 as score
	union all
	select 'a' name,'英语' clazz, 20 as score
	union all
	select 'b' name,'微积分' clazz, 70 as score
	union all
	select 'b' name,'数学' clazz, 75 as score
	union all
	select 'b' name,'现代' clazz, 71 as score
	union all
	select 'c' name,'物理' clazz, 70 as score
	union all
	select 'c' name,'音乐' clazz, 75 as score
	union all
	select 'c' name,'体育' clazz, 71 as score
),
tmp_b as (
select *,row_number() over(partition by name order by clazz) rk
from tmp_a
)
select name,
map_agg(rk,clazz) clazz,
map_agg(rk,score) score
from tmp_b group by name;

4. 拆分map

这里必须写死,没其他好方法,而且列是固定写死的。

clazz[1] 这里的1就是上面的放进去的rk的值,由于我们每个人最多只有3门课,

所以可以就取 clazz[1] clazz[2] clazz[3]

sql 复制代码
with tmp_a as (
	select 'a' name,'语文' clazz, 80 as score
	union all
	select 'a' name,'高数' clazz, 85 as score
	union all
	select 'a' name,'英语' clazz, 20 as score
	union all
	select 'b' name,'微积分' clazz, 70 as score
	union all
	select 'b' name,'数学' clazz, 75 as score
	union all
	select 'b' name,'现代' clazz, 71 as score
	union all
	select 'c' name,'物理' clazz, 70 as score
	union all
	select 'c' name,'音乐' clazz, 75 as score
	union all
	select 'c' name,'体育' clazz, 71 as score
),
tmp_b as (
select *,row_number() over(partition by name order by clazz) rk
from tmp_a
), 
tmp_c as (
select name,
map_agg(rk,clazz) clazz,
map_agg(rk,score) score
from tmp_b group by name
)
select name,
clazz[1] clazz_1,score[1] score_1,
clazz[2] clazz_2,score[2] score_2,
clazz[3] clazz_3,score[3] score_3
from tmp_c

最终显示如下,中午没睡觉想了一个中午,脑壳痛,看起来好像也不太复杂,

如果每个人的课程增加时,只需要在最后添加一行即可。

相关推荐
IvorySQL6 小时前
PostgreSQL 技术日报 (3月9日)|EXPLAIN ANALYZE 计时优化与复制语法讨论
数据库·postgresql·开源
用户8307196840828 小时前
Java 告别繁琐数据统计代码!MySQL 8 窗口函数真香
java·sql·mysql
stark张宇9 小时前
MySQL 核心内幕:从索引原理、字段选型到日志机制与外键约束,一篇打通数据库任督二脉
数据库·mysql·架构
倔强的石头_9 小时前
融合数据库架构实践:关系型、JSON与全文检索的“一库多能”深度解析
数据库
星辰员11 小时前
KingbaseES数据库:ksql 命令行用户与权限全攻略,从创建到删除
数据库
华仔啊1 天前
千万别给数据库字段加默认值 null!真的会出问题
java·数据库·后端
随风飘的云2 天前
MySQL的慢查询优化解决思路
数据库
IvorySQL2 天前
PostgreSQL 技术日报 (3月7日)|生态更新与内核性能讨论
数据库·postgresql·开源
赵渝强老师2 天前
【赵渝强老师】金仓数据库的数据文件
数据库·国产数据库·kingbase·金仓数据库
随逸1772 天前
《Milvus向量数据库从入门到实战,手把手搭建语义检索系统》
数据库