1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
create
table
tx(
id
int
primary
key
,
c1
char
(2),
c2
char
(2),
c3
int
);
insert
into
tx
values
(1 ,
'A1'
,
'B1'
,9),
(2 ,
'A2'
,
'B1'
,7),
(3 ,
'A3'
,
'B1'
,4),
(4 ,
'A4'
,
'B1'
,2),
(5 ,
'A1'
,
'B2'
,2),
(6 ,
'A2'
,
'B2'
,9),
(7 ,
'A3'
,
'B2'
,8),
(8 ,
'A4'
,
'B2'
,5),
(9 ,
'A1'
,
'B3'
,1),
(10 ,
'A2'
,
'B3'
,8),
(11 ,
'A3'
,
'B3'
,8),
(12 ,
'A4'
,
'B3'
,6),
(13 ,
'A1'
,
'B4'
,8),
(14 ,
'A2'
,
'B4'
,2),
(15 ,
'A3'
,
'B4'
,6),
(16 ,
'A4'
,
'B4'
,9),
(17 ,
'A1'
,
'B4'
,3),
(18 ,
'A2'
,
'B4'
,5),
(19 ,
'A3'
,
'B4'
,2),
(20 ,
'A4'
,
'B4'
,5);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
mysql>
select
* from tx;
+----+------+------+------+
|
id
| c1 | c2 | c3 |
+----+------+------+------+
| 1 | A1 | B1 | 9 |
| 2 | A2 | B1 | 7 |
| 3 | A3 | B1 | 4 |
| 4 | A4 | B1 | 2 |
| 5 | A1 | B2 | 2 |
| 6 | A2 | B2 | 9 |
| 7 | A3 | B2 | 8 |
| 8 | A4 | B2 | 5 |
| 9 | A1 | B3 | 1 |
| 10 | A2 | B3 | 8 |
| 11 | A3 | B3 | 8 |
| 12 | A4 | B3 | 6 |
| 13 | A1 | B4 | 8 |
| 14 | A2 | B4 | 2 |
| 15 | A3 | B4 | 6 |
| 16 | A4 | B4 | 9 |
| 17 | A1 | B4 | 3 |
| 18 | A2 | B4 | 5 |
| 19 | A3 | B4 | 2 |
| 20 | A4 | B4 | 5 |
+----+------+------+------+
20 rows
in
set
(0.00 sec)
mysql>
|
期望结果
1
2
3
4
5
6
7
8
9
|
+------+-----+-----+-----+-----+------+
|C1 |B1 |B2 |B3 |B4 |Total |
+------+-----+-----+-----+-----+------+
|A1 |9 |2 |1 |11 |23 |
|A2 |7 |9 |8 |7 |31 |
|A3 |4 |8 |8 |8 |28 |
|A4 |2 |5 |6 |14 |27 |
|Total |22 |24 |23 |40 |109 |
+------+-----+-----+-----+-----+------+
|
1. 利用SUM(IF()) 生成列 + WITH ROLLUP 生成汇总行,并利用 IFNULL将汇总行标题显示为 Total
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
mysql>
SELECT
IFNULL(c1,
'total'
) AS total,
SUM(IF(c2=
'B1'
,c3,0)) AS B1,
SUM(IF(c2=
'B2'
,c3,0)) AS B2,
SUM(IF(c2=
'B3'
,c3,0)) AS B3,
SUM(IF(c2=
'B4'
,c3,0)) AS B4,
SUM(IF(c2=
'total'
,c3,0)) AS total
FROM (
SELECT c1,IFNULL(c2,
'total'
) AS c2,SUM(c3) AS c3
FROM tx GROUP BY c1,c2
WITH ROLLUP
HAVING c1 IS NOT NULL
) AS A
GROUP BY c1
WITH ROLLUP;
+-------+------+------+------+------+-------+
| total | B1 | B2 | B3 | B4 | total |
+-------+------+------+------+------+-------+
| A1 | 9 | 2 | 1 | 11 | 23 |
| A2 | 7 | 9 | 8 | 7 | 31 |
| A3 | 4 | 8 | 8 | 8 | 28 |
| A4 | 2 | 5 | 6 | 14 | 27 |
| total | 22 | 24 | 23 | 40 | 109 |
+-------+------+------+------+------+-------+
5 rows
in
set
, 1 warning (0.00 sec)
|
2. 利用SUM(IF()) 生成列 + UNION 生成汇总行,并利用 IFNULL将汇总行标题显示为 Total
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
mysql>
select
c1,
sum
(
if
(c2=
'B1'
,C3,0)) AS B1,
sum
(
if
(c2=
'B2'
,C3,0)) AS B2,
sum
(
if
(c2=
'B3'
,C3,0)) AS B3,
sum
(
if
(c2=
'B4'
,C3,0)) AS B4,SUM(C3) AS TOTAL
from tx
group by C1
UNION
SELECT
'TOTAL'
,
sum
(
if
(c2=
'B1'
,C3,0)) AS B1,
sum
(
if
(c2=
'B2'
,C3,0)) AS B2,
sum
(
if
(c2=
'B3'
,C3,0)) AS B3,
sum
(
if
(c2=
'B4'
,C3,0)) AS B4,SUM(C3) FROM TX;
+-------+------+------+------+------+-------+
| c1 | B1 | B2 | B3 | B4 | TOTAL |
+-------+------+------+------+------+-------+
| A1 | 9 | 2 | 1 | 11 | 23 |
| A2 | 7 | 9 | 8 | 7 | 31 |
| A3 | 4 | 8 | 8 | 8 | 28 |
| A4 | 2 | 5 | 6 | 14 | 27 |
| TOTAL | 22 | 24 | 23 | 40 | 109 |
+-------+------+------+------+------+-------+
5 rows
in
set
(0.00 sec)
mysql>
|
3.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
mysql>
select
ifnull(c1,
'total'
),
sum
(
if
(c2=
'B1'
,C3,0)) AS B1,
sum
(
if
(c2=
'B2'
,C3,0)) AS B2,
sum
(
if
(c2=
'B3'
,C3,0)) AS B3,
sum
(
if
(c2=
'B4'
,C3,0)) AS B4,SUM(C3) AS TOTAL
from tx
group by C1 with rollup ;
+--------------------+------+------+------+------+-------+
| ifnull(c1,
'total'
) | B1 | B2 | B3 | B4 | TOTAL |
+--------------------+------+------+------+------+-------+
| A1 | 9 | 2 | 1 | 11 | 23 |
| A2 | 7 | 9 | 8 | 7 | 31 |
| A3 | 4 | 8 | 8 | 8 | 28 |
| A4 | 2 | 5 | 6 | 14 | 27 |
| total | 22 | 24 | 23 | 40 | 109 |
+--------------------+------+------+------+------+-------+
5 rows
in
set
(0.00 sec)
mysql>
|
4. 动态,适用于列不确定情况,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
mysql> SET @EE=
''
;
mysql> SELECT @EE:=CONCAT(@EE,
'SUM(IF(C2=\''
,C2,
'\''
,
',C3,0)) AS '
,C2,
','
) FROM (SELECT DISTINCT C2 FROM TX) A;
mysql> SET @QQ=CONCAT(
'SELECT ifnull(c1,\'total\'),'
,LEFT(@EE,LENGTH(@EE)-1),
' ,SUM(C3) AS TOTAL FROM TX GROUP BY C1 WITH ROLLUP'
);
Query OK, 0 rows affected (0.00 sec)
mysql> PREPARE stmt2 FROM @QQ;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> EXECUTE stmt2;
+--------------------+------+------+------+------+-------+
| ifnull(c1,
'total'
) | B1 | B2 | B3 | B4 | TOTAL |
+--------------------+------+------+------+------+-------+
| A1 | 9 | 2 | 1 | 11 | 23 |
| A2 | 7 | 9 | 8 | 7 | 31 |
| A3 | 4 | 8 | 8 | 8 | 28 |
| A4 | 2 | 5 | 6 | 14 | 27 |
| total | 22 | 24 | 23 | 40 | 109 |
+--------------------+------+------+------+------+-------+
5 rows
in
set
(0.00 sec)
mysql>
|
其实数据库中也可以用 CASE WHEN / DECODE
sum(if(c2='B1',C3,0)) AS B1
可改写为
sum(case c2 when 'B1' then C3 else 0 end) AS B1
原文地址:http://blog.chinaunix.net/u3/90603/showart_2017912.html
MySQL行列转换实例二
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
create
table
student
(
s_name
varchar
(20),
s_subject
varchar
(20),
s_point
int
);
insert
into
student
values
(
'张三'
,
'数学'
,86);
insert
into
student
values
(
'李四'
,
'数学'
,78);
insert
into
student
values
(
'张三'
,
'语文'
,67);
insert
into
student
values
(
'张三'
,
'英语'
,90);
insert
into
student
values
(
'李四'
,
'英语'
,88);
insert
into
student
values
(
'李四'
,
'语文'
,70);
insert
into
student
values
(
'王五'
,
'英语'
,90);
insert
into
student
values
(
'王五'
,
'数学'
,88);
insert
into
student
values
(
'王五'
,
'语文'
,70);
select
*
from
student;
|
方法一:
1
2
3
4
5
6
7
8
9
10
11
|
select
n.s_name
as
'姓名'
,n.shuxue
as
'数学'
,n.yuwen
as
'语文'
,n.yingyu
as
'英语'
,n.pingjun
as
'平均成绩'
,n.allcount
as
'总分'
from
(
select
s_name
as
s_name,
(
select
s_point
from
student
where
s.s_name=s_name
and
s_subject=
'数学'
)
as
shuxue,
(
select
s_point
from
student
where
s.s_name=s_name
and
s_subject=
'语文'
)
as
yuwen,
(
select
s_point
from
student
where
s.s_name=s_name
and
s_subject=
'英语'
)
as
yingyu,
avg
(s_point)
as
pingjun,
sum
(s_point)
as
allcount
from
student s
group
by
s_name
)n
order
by
allcount
desc
|
结果一:
1
2
3
4
5
6
7
8
|
+--------+--------+--------+--------+--------------+--------+
| 姓名 | 数学 | 语文 | 英语 | 平均成绩 | 总分 |
+--------+--------+--------+--------+--------------+--------+
| 王五 | 88 | 70 | 90 | 82.6667 | 248 |
| 张三 | 86 | 67 | 90 | 81.0000 | 243 |
| 李四 | 78 | 70 | 88 | 78.6667 | 236 |
+--------+--------+--------+--------+--------------+--------+
3 rows in set (0.00 sec)
|
方法二:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
SELECT
s_name,
MAX
(shuxue)
AS
数学,
MAX
(yuwen)
AS
语文,
MAX
(yingyu)
AS
英语
FROM
(
SELECT
s_name,
CASE
s_subject
WHEN
'数学'
THEN
s_point
END
AS
shuxue,
CASE
s_subject
WHEN
'语文'
THEN
s_point
END
AS
yuwen,
CASE
s_subject
WHEN
'英语'
THEN
s_point
END
AS
yingyu
FROM
student
)
AS
a
GROUP
BY
s_name
|
结果二:
1
2
3
4
5
6
7
8
|
+--------+--------+--------+--------+
| s_name | 数学 | 语文 | 英语 |
+--------+--------+--------+--------+
| 张三 | 86 | 67 | 90 |
| 李四 | 78 | 70 | 88 |
| 王五 | 88 | 70 | 90 |
+--------+--------+--------+--------+
3 rows in set (0.00 sec)
|