行列转换根据具体业务需求有跟多方式,这里介绍下个人的想法,话不多说,上示例
案例行转列:有一张成绩表(如下)
name |
subject |
score |
兮辰 |
语文 |
85 |
兮辰 |
数学 |
92 |
兮辰 |
英语 |
98 |
兮辰 |
体育 |
91 |
无尽 |
语文 |
90 |
无尽 |
数学 |
89 |
无尽 |
英语 |
93 |
无尽 |
体育 |
86 |
... |
... |
... |
展示如下:
name |
Chi |
Math |
Eng |
P.E |
兮辰 |
85 |
92 |
98 |
91 |
无尽 |
90 |
89 |
93 |
86 |
... |
... |
... |
... |
... |
首先先生成示例数据
with tb as ( select name, subject, score from values('兮辰','语文',85), ('兮辰','数学',92), ('兮辰','英语',98), ('兮辰','体育',91), ('无尽','语文',90), ('无尽','数学',89), ('无尽','英语',93), ('无尽','体育',86) t(name,subject,score) )
方式1:使用case when配合聚合函数max
select name, max(case when subject = '语文' then score end) as Chi, max(case when subject = '数学' then score end) as Math, max(case when subject = '英语' then score end) as Eng, max(case when subject = '体育' then score end) as PE from tb group by name; --结果如下: name chi math eng pe 兮辰 85 92 98 91 无尽 90 89 93 86
方式2:使用collect_list函数(根据需求不同,也可以使用collect_list+array_contains组合方式)
--该方式也有弊端,必须保障原表各科目顺序是一致的,否则从数组里拿出来的成绩将不对应 select name, score_list[0] as Chi, score_list[1] as Math, score_list[2] as Eng, score_list[3] as PE from ( select name, collect_list(score) as score_list from tb group by name )tmp; --结果如下: name chi math eng pe 兮辰 85 92 98 91 无尽 90 89 93 86
方式3:使用keyvalue函数,详细使用方法见阿里云文档
--将字符串'1:a;2:b'拆分为Key-Value对,返回其中key为1的value值 select keyvalue('1:a;2:b',1);--a
select name, keyvalue(subject,'语文') as Chi, keyvalue(subject,'数学') as Math, keyvalue(subject,'英语') as Eng, keyvalue(subject,'体育') as PE from ( select name, wm_concat(';',concat(subject,':',score)) as subject from ta group by name )tmp --结果如下: name chi math eng pe 兮辰 85 92 98 91 无尽 90 89 93 86
案例列转行:有一张成绩表(如下)
name |
Chi |
Math |
Eng |
P.E |
兮辰 |
85 |
92 |
98 |
91 |
无尽 |
90 |
89 |
93 |
86 |
... |
... |
... |
... |
... |
展示如下:
name |
subject |
score |
兮辰 |
语文 |
85 |
兮辰 |
数学 |
92 |
兮辰 |
英语 |
98 |
兮辰 |
体育 |
91 |
无尽 |
语文 |
90 |
无尽 |
数学 |
89 |
无尽 |
英语 |
93 |
无尽 |
体育 |
86 |
... |
... |
... |
首先生成示例数据
with tb as ( select name, Chi, Math, Eng, PE from values ('兮辰',85,92,98,91), ('无尽',90,89,93,86) t(name,Chi,Math,Eng,PE) )
方式1:使用union all,较为常用
select name, subject, score from ( select name,'语文' as subject,Chi as score from tb union all select name,'数学' as subject,Math as score from tb union all select name,'英语' as subject,Eng as score from tb union all select name,'体育' as subject,PE as score from tb ); --结果如下: name subject score 兮辰 语文 85 无尽 语文 90 兮辰 数学 92 无尽 数学 89 兮辰 英语 98 无尽 英语 93 兮辰 体育 91 无尽 体育 86
方式2:map函数+explode展开
select name, subject, score from ( select name, map( '语文',Chi, '数学',Math, '英语',Eng, '体育',PE ) as kv from tb ) tmp lateral view explode(kv) t as subject,score; --结果如下: name subject score 兮辰 体育 91 兮辰 数学 92 兮辰 英语 98 兮辰 语文 85 无尽 体育 86 无尽 数学 89 无尽 英语 93 无尽 语文 90
方式3:使用trans_array函数:将一行数据转为多行的UDTF,将列中存储的以固定分隔符格式分隔的数组转为多行。具体使用方法见阿里云文档
select name, split_part(subject,':',1) as subject, split_part(subject,':',2) as result from ( select trans_array(1,";",name,subject) as (name,subject) from ( select name, concat('语文',':',Chi,';','数学',':',Math,';','英语',':',Eng,';','体育',':',PE) as subject from tb )tmp1 )tmp2; --结果如下: name subject result 兮辰 语文 85 兮辰 数学 92 兮辰 英语 98 兮辰 体育 91 无尽 语文 90 无尽 数学 89 无尽 英语 93 无尽 体育 86
上面的示例只是提供了一种思路,可能与具体的业务需求不同,有不同想法的欢迎交流。
拜了个拜