SQL行转列
select name,
max(IF(subject ='chinese',score,0)) as 'chinese',
max(IF(subject ='math',score,0)) as 'math',
max(IF(subject ='english',score,0)) as 'english',
sum(score) as 'total'
from test_user
group by name
select name, sum(case subject when '数学' then source else 0 end) as '数学', sum(case subject when '英语' then source else 0 end) as '英语', sum(case subject when '语文' then source else 0 end) as '语文' from test group by name |
利用SUM(IF()) 生成列 + WITH ROLLUP 生成汇总行,并利用 IFNULL将汇总行标题显示为 Tota
-> 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;
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
-> ;
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 ;
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;
SELECT
DISTINCT
a.
name
,
(
SELECT
score
FROM
grade b
WHERE
a.
name
=b.
name
AND
b.course=
'语文'
)
AS
'语文'
,
(
SELECT
score
FROM
grade b
WHERE
a.
name
=b.
name
AND
b.course=
'数学'
)
AS
'数学'
,
(
SELECT
score
FROM
grade b
WHERE
a.
name
=b.
name
AND
b.course=
'英语'
)
AS
'英语'
FROM
grade a
SELECT
name
,
SUM
(
CASE
course
WHEN
'语文'
THEN
score
END
)
AS
'语文'
,
SUM
(
CASE
course
WHEN
'数学'
THEN
score
END
)
AS
'数学'
,
SUM
(
CASE
course
WHEN
'英语'
THEN
score
END
)
AS
'英语'
FROM
grade
GROUP
BY
name
DELIMITER &&
CREATE
PROCEDURE
sp_count()
BEGIN
#课程名称
DECLARE
course_n
VARCHAR
(20);
#所有课程数量
DECLARE
count
INT
;
#计数器
DECLARE
i
INT
DEFAULT
0;
#拼接SQL字符串
SET
@s =
'SELECT name'
;
SET
count
= (
SELECT
COUNT
(
distinct
course)
FROM
grade);
WHILE i <
count
DO
SET
course_n = (
SELECT
course
FROM
grade LIMIT i,1);
SET
@s = CONCAT(@s,
', SUM(CASE course WHEN '
,
'\''
, course_n,
'\''
,
' THEN score END )'
,
' AS '
,
'\''
,course_n,
'\''
);
SET
i = i+1;
END
WHILE;
SET
@s = CONCAT(@s,
' FROM grade GROUP BY name'
);
#用于调试
#
SELECT
@s;
PREPARE
stmt
FROM
@s;
EXECUTE
stmt;
END
&&
call sp_count();
第二种使用了分组,对每个分组分别处理。
第三种使用了存储过程,其实是第二种方法的动态化,先计算出所有课程的数量,然后对每个分组进行课程查询。
很明显前两种方法属于硬编码,增加课程后就需要修改SQL。而第三种则没有这种问题。