在平常的工作中或者面试中,我们可能有遇到过数据库的纵横表的转换问题。今天我们就来讨论下。
1.创建表
首先我们来创建一张表。
sql语句:
1
--
1. 创建数据表
2
if
OBJECT_ID
(
'
Score
'
)
is
not
null
drop
table
Score
3
4
create
table
Score
5
(
6
姓名
nvarchar
(
128
),
7
课程
nvarchar
(
128
),
8
分数
int
9
)
10
11
insert
into
Score
values
(
'
张三
'
,
'
语文
'
,
98
)
12
insert
into
Score
values
(
'
张三
'
,
'
数学
'
,
89
)
13
insert
into
Score
values
(
'
张三
'
,
'
物理
'
,
78
)
14
insert
into
Score
values
(
'
李四
'
,
'
语文
'
,
79
)
15
insert
into
Score
values
(
'
李四
'
,
'
数学
'
,
88
)
16
insert
into
Score
values
(
'
李四
'
,
'
物理
'
,
100
)
17
18
select
*
from
Score
执行结果:
2. 传统的纵横表转换
2.1 纵表转横表
先看看我们要转成的横表张什么样子:
既然这个表只有两列,那么可以根据姓名进行分组。先把姓名拼凑出来,后面的分数我们再想办法。
sql:
select
t.姓名
2
from
Score
as
t
3
group
by
t.姓名
结果:
分析:
- 我们先拿到语文这个科目的分数。既然我们用到了group by 语句,这里肯定要用聚合函数来求分数。
- 而且我们只需要语文这一科的成绩,分组出来的 一共有 3列 ,分别是 语文、数学、物理 。 那么就需要判断科目来取分数。
这里符合我们需求的 case 语句就登场了。他和c#中switch-case 作用一样。
sql case 语句语法:
case
字段
when
值1
then
结果
when
值2
then
结果2
...
else
默认结果
end
求语文的分数就简单了:
select
t.姓名,
SUM
(
case
t.课程
when
'
语文
'
then
t.分数
else
0
end
)
as
语文
from
Score
as
t
group
by
t.姓名
结果:
既然语文的分数取到了,其他科目改变下条件就可以了。
完整的sql:
select
t.姓名,
SUM
(
case
t.课程
when
'
语文
'
then
t.分数
else
0
end
)
as
语文,
SUM
(
case
t.课程
when
'
数学
'
then
t.分数
else
0
end
)
as
数学,
SUM
(
case
t.课程
when
'
物理
'
then
t.分数
else
0
end
)
as
物理
from
Score
as
t
group
by
t.姓名
OK,到这儿,我们传统方式的纵表转横表就大功告成了。
2.2 横表转纵表
那么我们可以把转换过来的横表再转换回去吗?
我们先把刚刚转好的表,插入一个新表ScoreHb 中。
1
--
转换的表插入新表
2
select
t.姓名,
3
SUM
(
case
t.课程
when
'
语文
'
then
t.分数
else
0
end
)
as
语文,
4
SUM
(
case
t.课程
when
'
数学
'
then
t.分数
else
0
end
)
as
数学,
5
SUM
(
case
t.课程
when
'
物理
'
then
t.分数
else
0
end
)
as
物理
6
into
ScoreHb
7
from
Score
as
t
8
group
by
t.姓名
这时ScoreHb 就是我们刚转换好的横表,我们再想办法把他转回来。
怎么转呢? 一步步来。我们也先把张三和李四的语文成绩查出来。
sql:
1
--
张三李四语文的分数
2
select
t.姓名,
3
'
语文
'
as
课程,
4
t.语文
as
分数
5
from
ScoreHb
as
t
结果:
还有两科的数据怎么办呢? 很简单,我们一个个都查出来,然后用 union all 把他们组合为一张表就可以了。
sql:
1
--
union all链接3个科目
2
select
t.姓名,
3
'
语文
'
as
课程,
4
t.语文
as
分数
5
from
ScoreHb
as
t
6
union
all
7
select
t.姓名,
8
'
数学
'
as
课程,
9
t.数学
as
分数
10
from
ScoreHb
as
t
11
union
all
12
select
t.姓名,
13
'
物理
'
as
课程,
14
t.物理
as
分数
15
from
ScoreHb
as
t
16
order
by
t.姓名 desc
结果:
这样,我们就把表又变回去了。
但是大家有没有觉得很麻烦呢?别急,我们有更简单的办法。下面为大家介绍pivot关系运算符。
3. 用pivot和unpivot运算符进行转换
pivot是sql server 2005 提供的运算符,所以只要数据库在05版本以上的都可以使用。主要用于行和列的转换。
3.1 pivot纵表转横表
sql:
1
select
2
t2.姓名,
3
t2.数学,
4
t2.物理,
5
t2.语文
6
from
Score
as
t1
7
pivot (
sum
(分数)
for
课程
in
(数学,语文,物理))
as
t2
结果:
是不是代码简洁多了。
pivot将原来表中 课程字段中的 数据行 数学,语文,物理 转换为列,并用sum取对应列的值。
我们只需要记住它的用法就可以了。
3.2 unpivot 横表转纵表
既然有privot可以纵表转横表。那么有没有运算符帮我们转回来呢?
答案是肯定的,他就是unpivot
sql:
1
select
2
*
3
from
4
ScoreHb
5
unpivot (分数
for
课程
in
(语文,数学,物理))
as
t4
结果:
unpivot 将 语文,数学,物理 列转为行,分数为新的一列存放对应的值。
是不是比我们之前一个个表查询拼接,方便了很多。

