打印本文 打印本文 关闭窗口 关闭窗口
SQL综合应用学习
作者:武汉SEO闵涛  文章来源:敏韬网  点击数3936  更新时间:2007/11/14 10:59:59  文章录入:mintao  责任编辑:mintao
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]  下一页

打印本文 打印本文 关闭窗口 关闭窗口