标签:
学校里面记录成绩,每个人的选课不一样,而且以后会添加课程,所以不需要把所有课程当作列。数据库grade里面数据如下图,假定每个人姓名都不一样,作为主键。本文以MySQL为基础,其他数据库会有些许语法不同。
下面介绍三种方法:
方法一:
|
1
2
3
4
5
|
SELECTDISTINCT a.name,(SELECTscoreFROMgrade bWHEREa.name=b.nameANDb.course=‘语文‘)AS‘语文‘,(SELECTscoreFROMgrade bWHEREa.name=b.nameANDb.course=‘数学‘)AS‘数学‘,(SELECTscoreFROMgrade bWHEREa.name=b.nameANDb.course=‘英语‘)AS‘英语‘FROMgrade a |
方法二:
|
1
2
3
4
5
|
SELECTname,SUM(CASE courseWHEN ‘语文‘THENscoreEND)AS‘语文‘,SUM(CASE courseWHEN ‘数学‘THENscoreEND)AS‘数学‘,SUM(CASE courseWHEN ‘英语‘THENscoreEND)AS‘英语‘FROMgradeGROUPBYname |
方法三:
|
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
|
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 DOSET 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。而第三种则没有这种问题。
Note:
MySQL中不能在一个存储过程中删除另一个存储过程,只能调用另一个存储过程
本来想在方法三里面写上:DROP PROCEDURE IF EXISTS sp_count();这是错误的。调试的时候如果写错了,只能手动删除了,也没找到好方法。
参考资料:
2013-8-8更新:
方法二还可以使用IF语句。
如下所示:
|
1
2
3
4
5
|
SELECT name,SUM(IF (course = ‘语文‘ , score , null ) ) as ‘语文‘,SUM(IF (course = ‘数学‘ , score , null ) ) as ‘数学‘,SUM(IF (course = ‘英语‘ , score , null ) ) as ‘英语 ‘FROM grade GROUP BY name |
标签:
原文地址:http://www.cnblogs.com/mn-b/p/5197080.html