关于优雅的使用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

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

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

所以可以就取 clazz1 clazz2 clazz3

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

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

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

相关推荐
AAA代码批发商7 分钟前
Days 39 Linux C 开发之 SQLite 数据库完整学习笔记
linux·c语言·数据库
笑梦无境7 分钟前
mysql的安装及配置(3)
数据库·mysql·adb
电商API_180079052478 分钟前
跨境1688代采商家,如何借助API打通供应链,实现效率跃迁
大数据·数据库·网络爬虫
小雪崩9 分钟前
嵌入式学习 day40:数据库
数据库·学习
Aloudata27 分钟前
语义层 vs MCP 工具层:Agent 调用数据时,语义应该放在哪一层
数据库·数据分析·chatbi·data agent·语义层
zcmodeltech27 分钟前
源网荷储一体化沙盘模型多场景控制系统设计——基于STM32与Modbus RTU的源网荷储、多能互补、冷热电三联供全场景联动方案,服务范围覆盖全国
数据库·人工智能·stm32·单片机·嵌入式硬件
数智启示录31 分钟前
PostgreSQL 执行计划实战(第 9 篇):SQL 和索引没变,计划为什么突然慢一百倍
数据库·经验分享·sql·postgresql·面试
Gent_倪1 小时前
MySQL分库、分表、分区详解
数据库·mysql
额额额对了1 小时前
Linux 数据库开发实战:使用 C 语言与 SQLite3 构建轻量级终端词典
linux·数据库·oracle
qq_246839751 小时前
postgresql xxhash64 哈希函数实现
数据库·postgresql·哈希算法