article/SQL-行转列与列转行.md
2023-06-04 15:59:11 +08:00

6.5 KiB
Raw Blame History

SQL 讲解 —— 行转列 与 列转行

行转列

题目1

描述

name  subject  score
张三    语文     78
张三    数学     88
张三    英语 	 98
李四    语文     89
李四    数学     76
李四    英语     90
王五    语文	 99
王五	  数学	 66
王五	  英语	 91

name  语文  数学  英语
张三   78   88    98
李四   89   76    90
王五   99   66    91

脚本

create table SQL_1
(
    name varchar(20),
    subject varchar(20),
    score float
);
insert into SQL_1 (name, subject, score) values ('张三', '语文', 78);
insert into SQL_1 (name, subject, score) values ('张三', '数学', 88);
insert into SQL_1 (name, subject, score) values ('张三', '英语', 98);
insert into SQL_1 (name, subject, score) values ('李四', '语文', 89);
insert into SQL_1 (name, subject, score) values ('李四', '数学', 76);
insert into SQL_1 (name, subject, score) values ('李四', '英语', 90);
insert into SQL_1 (name, subject, score) values ('王五', '语文', 99);
insert into SQL_1 (name, subject, score) values ('王五', '数学', 66);
insert into SQL_1 (name, subject, score) values ('王五', '英语', 91);
select * from SQL_1;

解题步骤

1 确定分组列,转换列,数据列

2 生成伪列

3 做分组查询

4 选择合适的聚合函数

两步法

公式:
select 分组列,
       聚合函数(m1) as 列名1,
       聚合函数(m2) as 列名2,
       聚合函数(m3) as 列名3
from (select *,
             case 转换列 when 转换列值1 then 数据列 else ... end as m1,
             case 转换列 when 转换列值2 then 数据列 else ... end as m2,
             case 转换列 when 转换列值3 then 数据列 else ... end as m3
      from 表名) 临时表名
group by 分组列;
解题SQL
select name,
       sum(m1) as 语文,
       sum(m2) as 数学,
       sum(m3) as 英语
from (select *,
             case subject when '语文' then score else 0 end as m1,
             case subject when '数学' then score else 0 end as m2,
             case subject when '英语' then score else 0 end as m3
      from sql_1) tmp
group by name;

一步法

公式:
select 分组列,
       聚合函数(case 转换列 when 转换列值1 then 数据列 else ... end) as 列名1,
	   聚合函数(case 转换列 when 转换列值2 then 数据列 else ... end) as 列名2,
	   聚合函数(case 转换列 when 转换列值3 then 数据列 else ... end) as 列名3
	   ...
from 表名
group by 分组列;

select 分组列,
       聚合函数(case when 转换列=转换列值1 then 数据列 else ... end) as 列名1,
	   聚合函数(case when 转换列=转换列值2 then 数据列 else ... end) as 列名2,
	   聚合函数(case when 转换列=转换列值3 then 数据列 else ... end) as 列名3
	   ...
from 表名
group by 分组列;
解题SQL
select name,
       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 sql_1
group by name;

select name,
       sum(case when subject = '语文' then score else 0 end) as 语文,
       sum(case when subject = '数学' then score else 0 end) as 数学,
       sum(case when subject = '英语' then score else 0 end) as 英语
from sql_1
group by name;

题目2

描述

# 日期        结果
# 2022-01-01  胜
# 2022-01-01  胜
# 2022-01-02  负
# 2022-01-02  负
# 2022-01-01  负
# 2022-01-02  负
# 2022-01-02  胜

# 日期         胜 负
# 2022-01-01  2  1
# 2022-01-02  1  3

脚本

create table SQL_2(
   ddate varchar(10), result varchar(2)
);

insert into SQL_2 (ddate, result) values('2022-01-01','胜');
insert into SQL_2 (ddate, result) values('2022-01-01','胜');
insert into SQL_2 (ddate, result) values('2022-01-02','负');
insert into SQL_2 (ddate, result) values('2022-01-02','负');
insert into SQL_2 (ddate, result) values('2022-01-01','负');
insert into SQL_2 (ddate, result) values('2022-01-02','负');
insert into SQL_2 (ddate, result) values('2022-01-02','胜');
select * from SQL_2;

解题SQL

select ddate,
       sum(case when result = '胜' then 1 else 0 end) as ,
       sum(case when result = '负' then 1 else 0 end) as 
from sql_2
group by ddate;

列转行

题目3

描述

name  语文  数学  英语 
张三   78   88    98
李四   89   76    90
王五   99   66    91 

name  subject  score
张三    语文     78
张三    数学     88
张三    英语 	 98
李四    语文     89
李四    数学     76
李四    英语     90
王五    语文	 99
王五	  数学	 66
王五	  英语	 91

脚本

CREATE TABLE SQL_3 (
	name varchar(20),
    语文 float,
    数学 float,
    英语 float
);

insert into SQL_3 (name, '语文', '数学', '英语') values ('张三', 78, 88, 98);
insert into SQL_3 (name, '语文', '数学', '英语') values ('李四', 89, 76, 90);
insert into SQL_3 (name, '语文', '数学', '英语') values ('王五', 99, 66, 91);

解题步骤

1 确定转换列,非转换列

2 生成新列

3 使用union或union all 进行合并

4 根据需要进行order by

公式

SELECT 非转换列, '转换列1' AS 新转换列名, 转换列1 AS 新数据列名 FROM 表名
UNION ALL
SELECT 非转换列, '转换列2' AS 新转换列名, 转换列2 AS 新数据列名 FROM 表名
UNION ALL
SELECT 非转换列, '转换列3' AS 新转换列名, 转换列3 AS 新数据列名 FROM 表名
ORDER BY ...;

解题SQL

SELECT name,'语文' AS subject,语文 AS score FROM SQL_3
UNION ALL
SELECT name,'数学' AS subject,数学 AS score FROM SQL_3
UNION ALL
SELECT name,'英语' AS subject,英语 AS score FROM SQL_3
ORDER BY name ASC, subject DESC;

题目4

描述

Q1     Q2     Q3     Q4
1000   2000   3000   4000

季度   业绩
Q1    1000
Q2    2000
Q3    3000
Q4    4000

脚本

CREATE TABLE SQL_4 (
	Q1 int, Q2 int, Q3 int, Q4 int
);

insert into SQL_4 values (1000, 2000, 3000, 4000);

解题SQL

SELECT  'Q1' AS 季度, Q1 AS 业绩 FROM SQL_4
UNION ALL
SELECT 'Q2' AS 季度, Q2 AS 业绩 FROM SQL_4
UNION ALL
SELECT 'Q3' AS 季度, Q3 AS 业绩 FROM SQL_4
UNION ALL
SELECT 'Q4' AS 季度, Q4 AS 业绩 FROM SQL_4
ORDER BY 季度;

技巧:

扩展列select ... as 新列名

减少列:直接不写

扩展行union/ union all

减少行: 聚合函数