|
UPDATE 和 INSERT 写操作也应照此行事。从数据库原理的关系运算的角度来看 INSERT、 UPDATE 和 DELETE 这些写操作都属于典型的"选择(Selection)"运算,UPDATE 和 INSERT 而且还是"投影(Projection)"运算,它们都是这些关系运算的"写"应用的表现形式。 其实,查询的目的也本来无非就是浏览、删除、更 新或插入。通常写操作也比读操作消耗更大,如果索引过多,只会降低效率。
选择"子查询"还是"连接"在效率是有差别的,但最关键的差别还是表现在查询的结果 集的读写性上,开发人员在写一个"只读"应用的查询记录集时,"子查询"和"连接"各自 的效率就是应该首先考虑的问题,但是如果要实现"可写"应用的查询结果集,则无论是 相关还是非相关子查询都是在复杂应用中难以避免的。
以上解决方案中,应该说第一种方法,简洁有效,很有创意,是值得推荐的方法。当然, 最简单的写法应该是:
DELETE T FROM T,T T1 WHERE T.学生ID=T1.学生ID and T.课程ID=T.课程ID and T.F < T1.F
其实这就是方法一的"标准"(但确实实不是《ANSI/ISO SQL》标准)连接写法,以下各 题答案为了便于读者理解,一般不采用这种写法,这也是《ANSI/ISO SQL》标准所鼓 励的,JOIN 确实更容易地表达表之间的关系,有兴趣的读者可自行改写。如果使用 "*="实现两表以上的外连接时,要注意此时 WHERE 子句的 AND 条件是有顺序的,尽 管《ANSI/ISO SQL》标准不允许 WHERE 条件的顺序影响查询结果,但是 FROM 子句 的各表连接的顺序可以影响查询结果。
2.列印各科成绩最高和最低的相关记录: (就是各门课程的最高、最低分的学生和老师) 课程ID,课程名称, 最高分,学生ID,学生姓名,教师ID,教师姓名, 最低分,学生ID,学生姓名,教师ID,教师姓名
如果这道题要是仅仅求出各科成绩最高分或最低分,则是一道非常简单的题了:
SELECT L.课程ID, MAX(L.课程名称), MAX(L.成绩) AS 最高分, MIN(L.成绩) AS 最低分 FROM 成绩表 L GROUP BY L.课程ID 但是,刁钻的题目却是要列出各科最高和最低成绩的相关记录,这也往往才是真正需求。 既然已经选出各科最高和最低分,那么,剩下的就是把学生和教师的信息并入这个结果 集。如果照这样写下去,非常麻烦,因为要添加的字段太多了,很快就使代码变得难于 管理。还是换个思路吧:
SELECT L.课程ID,L.课程名称,L.[成绩] AS 最高分,L.[学生ID],L.[学生姓名],L.[教师ID],L.[教师姓名] ,R.[成绩] AS 最低分,R.[学生ID],R.[学生姓名],R.[教师ID],R.[教师姓名] FROM 成绩表 L JOIN 成绩表 AS R ON L.[课程ID] = R.[课程ID] WHERE L.[成绩] = (SELECT MAX(IL.[成绩]) FROM 成绩表 AS [IL] WHERE L.[课程ID] = IL.[课程ID] GROUP BY IL.[课程ID] ) AND R.[成绩] = (SELECT MIN(IR.[成绩]) FROM 成绩表 AS [IR] WHERE R.[课程ID] = IR.[课程ID] GROUP BY IR.[课程ID] )
乍一看答案,好像很复杂,其实如果掌握了构造交叉透视表的基本方法和相关子查询的 知识,问题迎刃而解。由于最低和最高分都是针对课程信息的,该答案巧妙地把课程信 息合并到了最高分的数据集中,当然也可以合并到最低分中。代码中规中矩,风格很好, 可读性也是不错的。
3.按平均成绩从高到低顺序,列印所有学生的四门(数学,语文,英语,政治)课程成绩: (就是每个学生的四门课程的成绩单) 学生ID,学生姓名,数学,语文,英语,政治,有效课程数,有效平均分 (注: 有效课程即在 T 表中有该学生的成绩记录,如不明白可不列印"有效课程数"和"有效平均分")
需要说明的是: 题目之所以明确提出"四门(数学,语文,英语,政治)课程"是有道理的, 因为实现时,的确无法避免使原基本表中的行上的数据的值影响列,这又是一个典型的 "行变列"的相关子查询:
SELECT 学生ID,MAX(学生姓名) AS 学生姓名, (SELECT 成绩 FROM 成绩表 WHERE 学生ID=T.学生ID AND 课程ID=''''K1'''') AS 数学 , (SELECT 成绩 FROM 成绩表 WHERE 学生ID=T.学生ID AND 课程ID=''''K2'''') AS 语文 , (SELECT 成绩 FROM 成绩表 WHERE 学生ID=T.学生ID AND 课程ID=''''K3'''') AS 英语 , (SELECT 成绩 FROM 成绩表 WHERE 学生ID=T.学生ID AND 课程ID=''''K4'''') AS 政治 , COUNT(*) AS 有效课程数, AVG(T.成绩) AS 平均成绩 FROM 成绩表 AS T GROUP BY 学生ID ORDER BY 平均成绩
这可以说也是一个很规矩的解法,在这种应用场合,子查询要比联接代码可读性强得多。 如果数据库引擎认为把它解析成联接更好,那就由它去吧,其实本来相关子查询也肯定含有连接。 这里再补充一下,在实际应用中如果再加一张表 Ranks(Rank,MinValue,MaxValue):
┌─────┬─────┬─────┐ │ Rank │ MinValue │ MaxValue │ ├─────┼─────┼─────┤ │ A │ 90 │ 100 │ ├─────┼─────┼─────┤ │ B │ 80 │ 89 │ ├─────┼─────┼─────┤ │ C │ 70 │ 79 │ ├─────┼─────┼─────┤ │ D │ 60 │ 69 │ ├─────┼─────┼─────┤ │ E │ 0 │ 59 │ └─────┴─────┴─────┘
就可以实现一个非常有实用价值的应用:
select 学生ID,MAX(学生姓名) as 学生姓名 ,(select 成绩 from 成绩表 t where 学生ID=T0.学生ID and 课程ID=''''K1'''') as 数学 ,(SELECT max(Rank) from Ranks ,成绩表 t where t.成绩 >= Ranks.MinValue and t.成绩 <= Ranks.MaxValue and t.学生ID=T0.学生ID and t.课程ID=''''K1'''' ) as 数学级别 ,(select 成绩 from 成绩表 t where 学生ID=T0.学生ID and 课程ID=''''K2'''') as 语文 ,(SELECT min(Rank) from Ranks ,成绩表 t where t.成绩 >= Ranks.MinValue and t.成绩 <= Ranks.MaxValue and t.学生ID=T0.学生ID and t.课程ID=''''K2'''' ) as 语文级别 ,(select 成绩 from 成绩表 t where 学生ID=T0.学生ID and 课程ID=''''K3'''') as 英语 ,(SELECT max(Rank) from Ranks ,成绩表 t where t.成绩 >= Ranks.MinValue and t.成绩 <= Ranks.MaxValue and t.学生ID=T0.学生ID and t.课程ID=''''K3'''' ) as 英语级别 ,(select 成绩 from 成绩表 t where 学生ID=T0.学生ID and 课程ID=''''K4'''') as 政治 ,(SELECT min(Rank) from Ranks ,成绩表 t where t.成绩 >= Ranks.MinValue and t.成绩 &l 上一页 [1] [2] [3] [4] 下一页 [办公软件]在sybase中插入图片、PDF、文本文件 [办公软件]安装Sybase ASE [办公软件]linux指令大全(完整篇) [办公软件]Linux新手入门常用命令大全 [办公软件]在RedHat Linux 9里安装gaim0.80 [办公软件]浅谈Linux 下Java 1.5 汉字方块问题解决方法 [办公软件]Linux程序员必读:中文化与GB18030标准 [办公软件]linux指令大全 [办公软件]制作Linux启动盘的四种方法 [办公软件]Linux文件系统的反删除方法
|