小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

SQL綜合應(yīng)用學(xué)習(xí)

 qzg589 2005-09-09

SQL綜合應(yīng)用學(xué)習(xí)

[日期:2005-07-08] 來源:CSDN  作者: [字體: ]

看完測試完下面這些試題,你的SQL水平一定會有新的提高。

下面我們先看一下題設(shè):
二維表 T(F1,F2,F3,F4,F5,F6,F7) 表示如下關(guān)系:
┌─────┬────┬─────┬─────┬─────┬─────┬─────┐
│  學(xué)生ID  │學(xué)生姓名│  課程ID  │ 課程名稱 │   成績   │  教師ID  │ 教師姓名 │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│    S3    │   王五 │    K4    │   政治   │    53    │    T4    │  趙老師  │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│    S1    │   張三 │    K1    │   數(shù)學(xué)   │    61    │    T1    │  張老師  │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│    S2    │   李四 │    K3    │   英語   │    88    │    T3    │  李老師  │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│    S1    │   張三 │    K4    │   政治   │    77    │    T4    │  趙老師  │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│    S2    │   李四 │    K4    │   政治   │    67    │    T5    │  周老師  │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│    S3    │   王五 │    K2    │   語文   │    90    │    T2    │  王老師  │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│    S3    │   王五 │    K1    │   數(shù)學(xué)   │    55    │    T1    │  張老師  │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│    S1    │   張三 │    K2    │   語文   │    81    │    T2    │  王老師  │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│    S4    │   趙六 │    K2    │   語文   │    59    │    T1    │  王老師  │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│    S1    │   張三 │    K3    │   英語   │    37    │    T3    │  李老師  │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│    S2    │   李四 │    K1    │   數(shù)學(xué)   │    81    │    T1    │  張老師  │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│   ....   │        │          │          │          │          │          │
├─────┼────┼─────┼─────┼─────┼─────┼─────┤
│   ....   │        │          │          │          │          │          │
└─────┴────┴─────┴─────┴─────┴─────┴─────┘
為便于大家更好的理解,我們將 T 表起名為"成績表"

1.如果 T 表還有一字段 F 數(shù)據(jù)類型為自動增量整型(唯一,不會重復(fù)),
  而且 T 表中含有除 F 字段外,請刪除其它字段完全相同的重復(fù)多余的臟記錄數(shù)據(jù):

  本問題就是一個清理"邏輯重復(fù)"記錄的問題,當(dāng)然,這種情況完全可以利用主鍵約束來
  杜絕!然而,現(xiàn)實情況經(jīng)常是原始數(shù)據(jù)在"洗滌"后,方可安全使用,而且邏輯主鍵過早的
  約束,將會給采集原始數(shù)據(jù)帶來不便,例如:從刷卡機(jī)上讀取考勤記錄。到了應(yīng)用數(shù)據(jù)
  的時候,臟數(shù)據(jù)就該被掃地出門了! 之所以題中要保留一個自動標(biāo)識列,是因為它的確
  是下面答案所必須的前提:

  DELETE L
    FROM "成績表" L
         JOIN "成績表" R
                       ON L."學(xué)生ID" = R."學(xué)生ID" AND L."課程ID" = R."課程ID" AND L.F > R.F

  這是思路最精巧且最直接有效的方法之一。用不等自聯(lián)接,正好可以將同一組重復(fù)數(shù)
  據(jù)中 F 字段值最小的那一條留下,并選出其它的刪掉,如果只有一條,自然也不會被選
  中了。這里還要強調(diào)一下,大家一定要分清楚被操作的基本表也就是 DELETE 關(guān)鍵字
  后的表和過濾條件所使用的由基本表連接而成的二維表數(shù)據(jù)集,也就是 FROM 子句的
  全部。在自連接的 FROM 子句至少要取一個別名來引用基本表。別名的使用在編寫大
  量類似結(jié)構(gòu)的 SQL 時非常方便,而且利于統(tǒng)一程序構(gòu)造動態(tài) SQL。如有必要加強條件,
  還可繼續(xù)使用 WHERE 子句。如果上面的例子還不夠直觀,下面模仿一個不等自聯(lián)接,
  有一組數(shù) (1,2,3),作一個不等自聯(lián)接,令左子集大于右子集,是:
  2 1
  3 1
  3 2
  如果現(xiàn)在選出左子集,就是 2 和 3 了。1 在右邊沒有比它更小的數(shù)據(jù)可以與之匹配,
  因此被過濾了。如果數(shù)據(jù)大量重復(fù),效率會差強人意,幸虧不是 SELECT ,而是 DELETE
  無需返回結(jié)果集,影響自然小多了。

  DELETE T
  FROM 成績表 T
  WHERE F NOT IN (SELECT MIN(F)
                    FROM 成績表 I
                GROUP BY I.學(xué)生ID,I.課程ID
                  HAVING COUNT(*)>1
                 )
        AND F NOT IN (SELECT MIN(F)
                        FROM 成績表 I
                    GROUP BY I.學(xué)生ID, I.課程ID
                      HAVING COUNT(*)=1
                     )

  這種方法思路很簡單,就像翻譯自然語言,很精確地描述了符合條件記錄的特性,甚至
  第二個條件的確多余。至少應(yīng)該用一個 >= 號合并這兩個條件或只保留任意一個條件,
  提高效率。

  DELETE T
    FROM 成績表 T
   WHERE F > (SELECT MIN(F)
                FROM 成績表 AS I
               WHERE I.學(xué)生ID = T.學(xué)生ID
                     AND I.課程ID = T.課程ID
            GROUP BY I.學(xué)生ID, I.課程ID
             )

  這種方法,基本上是方法一的相關(guān)子查詢版本,了解笛卡爾積的讀者能會好理解些,而
  且用到了統(tǒng)計函數(shù),因此效率不是太高。細(xì)心的讀者會發(fā)現(xiàn)子查詢里的 GROUP BY 子
  句沒有必要,去掉它應(yīng)該會提高一些效率的。

  關(guān)于 DELETE 語句的調(diào)試,有經(jīng)驗的程序員都會先用無害的 SELECT 暫時代替危險的
  DELETE。例如:

  SELECT L.*
  --DELECT L 暫時注釋掉
    FROM "成績表" L
         JOIN "成績表" R
            ON L."學(xué)生ID" = R."學(xué)生ID" AND L."課程ID" = R."課程ID" AND L.F>R.F

  這樣,極大地減小了在線數(shù)據(jù)被無意破壞的可能性,當(dāng)然數(shù)據(jù)提前備份也很重要。同理
  UPDATE 和 INSERT 寫操作也應(yīng)照此行事。從數(shù)據(jù)庫原理的關(guān)系運算的角度來看 INSERT、
  UPDATE 和 DELETE 這些寫操作都屬于典型的"選擇(Selection)"運算,UPDATE 和 INSERT
  而且還是"投影(Projection)"運算,它們都是這些關(guān)系運算的"寫"應(yīng)用的表現(xiàn)形式。
  其實,查詢的目的也本來無非就是瀏覽、刪除、更
  新或插入。通常寫操作也比讀操作消耗更大,如果索引過多,只會降低效率。

  選擇"子查詢"還是"連接"在效率是有差別的,但最關(guān)鍵的差別還是表現(xiàn)在查詢的結(jié)果
  集的讀寫性上,開發(fā)人員在寫一個"只讀"應(yīng)用的查詢記錄集時,"子查詢"和"連接"各自
  的效率就是應(yīng)該首先考慮的問題,但是如果要實現(xiàn)"可寫"應(yīng)用的查詢結(jié)果集,則無論是
  相關(guān)還是非相關(guān)子查詢都是在復(fù)雜應(yīng)用中難以避免的。

  以上解決方案中,應(yīng)該說第一種方法,簡潔有效,很有創(chuàng)意,是值得推薦的方法。當(dāng)然,
  最簡單的寫法應(yīng)該是:

  DELETE T
    FROM T,T T1
   WHERE T.學(xué)生ID=T1.學(xué)生ID and T.課程ID=T.課程ID and T.F < T1.F

  其實這就是方法一的"標(biāo)準(zhǔn)"(但確實實不是《ANSI/ISO SQL》標(biāo)準(zhǔn))連接寫法,以下各
  題答案為了便于讀者理解,一般不采用這種寫法,這也是《ANSI/ISO SQL》標(biāo)準(zhǔn)所鼓
  勵的,JOIN 確實更容易地表達(dá)表之間的關(guān)系,有興趣的讀者可自行改寫。如果使用
  "*="實現(xiàn)兩表以上的外連接時,要注意此時 WHERE 子句的 AND 條件是有順序的,盡
  管《ANSI/ISO SQL》標(biāo)準(zhǔn)不允許 WHERE 條件的順序影響查詢結(jié)果,但是 FROM 子句
  的各表連接的順序可以影響查詢結(jié)果。

2.列印各科成績最高和最低的相關(guān)記錄: (就是各門課程的最高、最低分的學(xué)生和老師)
  課程ID,課程名稱, 最高分,學(xué)生ID,學(xué)生姓名,教師ID,教師姓名,  最低分,學(xué)生ID,學(xué)生姓名,教師ID,教師姓名

  如果這道題要是僅僅求出各科成績最高分或最低分,則是一道非常簡單的題了:

 SELECT L.課程ID, MAX(L.課程名稱), MAX(L.成績) AS 最高分, MIN(L.成績) AS 最低分
    FROM 成績表 L
GROUP BY L.課程ID
 
  但是,刁鉆的題目卻是要列出各科最高和最低成績的相關(guān)記錄,這也往往才是真正需求。
  既然已經(jīng)選出各科最高和最低分,那么,剩下的就是把學(xué)生和教師的信息并入這個結(jié)果
  集。如果照這樣寫下去,非常麻煩,因為要添加的字段太多了,很快就使代碼變得難于
  管理。還是換個思路吧:

  SELECT L.課程ID,L.課程名稱,L.[成績] AS 最高分,L.[學(xué)生ID],L.[學(xué)生姓名],L.[教師ID],L.[教師姓名]
                            ,R.[成績] AS 最低分,R.[學(xué)生ID],R.[學(xué)生姓名],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]
                     )

  乍一看答案,好像很復(fù)雜,其實如果掌握了構(gòu)造交叉透視表的基本方法和相關(guān)子查詢的
  知識,問題迎刃而解。由于最低和最高分都是針對課程信息的,該答案巧妙地把課程信
  息合并到了最高分的數(shù)據(jù)集中,當(dāng)然也可以合并到最低分中。代碼中規(guī)中矩,風(fēng)格很好,
  可讀性也是不錯的。

3.按平均成績從高到低順序,列印所有學(xué)生的四門(數(shù)學(xué),語文,英語,政治)課程成績: (就是每個學(xué)生的四門課程的成績單)
  學(xué)生ID,學(xué)生姓名,數(shù)學(xué),語文,英語,政治,有效課程數(shù),有效平均分
  (注: 有效課程即在 T 表中有該學(xué)生的成績記錄,如不明白可不列印"有效課程數(shù)"和"有效平均分")

  需要說明的是: 題目之所以明確提出"四門(數(shù)學(xué),語文,英語,政治)課程"是有道理的,
  因為實現(xiàn)時,的確無法避免使原基本表中的行上的數(shù)據(jù)的值影響列,這又是一個典型的
  "行變列"的相關(guān)子查詢:

SELECT 學(xué)生ID,MAX(學(xué)生姓名) AS 學(xué)生姓名,
 (SELECT 成績 FROM 成績表 WHERE 學(xué)生ID=T.學(xué)生ID AND 課程ID=‘K1‘) AS 數(shù)學(xué) ,
        (SELECT 成績 FROM 成績表 WHERE 學(xué)生ID=T.學(xué)生ID AND 課程ID=‘K2‘) AS 語文 ,
        (SELECT 成績 FROM 成績表 WHERE 學(xué)生ID=T.學(xué)生ID AND 課程ID=‘K3‘) AS 英語 ,
        (SELECT 成績 FROM 成績表 WHERE 學(xué)生ID=T.學(xué)生ID AND 課程ID=‘K4‘) AS 政治 ,
        COUNT(*) AS 有效課程數(shù), AVG(T.成績) AS 平均成績
    FROM 成績表 AS T
GROUP BY 學(xué)生ID
ORDER BY 平均成績

  這可以說也是一個很規(guī)矩的解法,在這種應(yīng)用場合,子查詢要比聯(lián)接代碼可讀性強得多。
  如果數(shù)據(jù)庫引擎認(rèn)為把它解析成聯(lián)接更好,那就由它去吧,其實本來相關(guān)子查詢也肯定含有連接。
  這里再補充一下,在實際應(yīng)用中如果再加一張表 Ranks(Rank,MinValue,MaxValue):

  ┌─────┬─────┬─────┐
  │   Rank   │ MinValue │ MaxValue │
  ├─────┼─────┼─────┤
  │    A     │    90    │   100    │
  ├─────┼─────┼─────┤
  │    B     │    80    │    89    │
  ├─────┼─────┼─────┤
  │    C     │    70    │    79    │
  ├─────┼─────┼─────┤
  │    D     │    60    │    69    │
  ├─────┼─────┼─────┤
  │    E     │     0    │    59    │
  └─────┴─────┴─────┘

  就可以實現(xiàn)一個非常有實用價值的應(yīng)用:

select 學(xué)生ID,MAX(學(xué)生姓名) as 學(xué)生姓名
       ,(select 成績 from 成績表 t where 學(xué)生ID=T0.學(xué)生ID and 課程ID=‘K1‘) as 數(shù)學(xué)
       ,(SELECT max(Rank) from Ranks ,成績表 t
           where t.成績 >= Ranks.MinValue
                 and t.成績 <= Ranks.MaxValue
                 and t.學(xué)生ID=T0.學(xué)生ID and t.課程ID=‘K1‘ 
           ) as 數(shù)學(xué)級別
       ,(select 成績 from 成績表 t where 學(xué)生ID=T0.學(xué)生ID and 課程ID=‘K2‘) as 語文
       ,(SELECT min(Rank)
           from Ranks ,成績表 t
           where t.成績 >= Ranks.MinValue
                 and t.成績 <= Ranks.MaxValue
                 and t.學(xué)生ID=T0.學(xué)生ID and t.課程ID=‘K2‘ 
           ) as 語文級別
       ,(select 成績 from 成績表 t where 學(xué)生ID=T0.學(xué)生ID and 課程ID=‘K3‘) as 英語
       ,(SELECT max(Rank)
           from Ranks ,成績表 t
           where t.成績 >= Ranks.MinValue
                 and t.成績 <= Ranks.MaxValue
                 and t.學(xué)生ID=T0.學(xué)生ID and t.課程ID=‘K3‘ 
           ) as 英語級別
       ,(select 成績 from 成績表 t where 學(xué)生ID=T0.學(xué)生ID and 課程ID=‘K4‘) as 政治
       ,(SELECT min(Rank)
           from Ranks ,成績表 t
           where t.成績 >= Ranks.MinValue
                 and t.成績 <= Ranks.MaxValue
                 and t.學(xué)生ID=T0.學(xué)生ID and t.課程ID=‘K4‘ 
           ) as 政治級別
       ,count(*),avg(t0.成績)
       ,(SELECT max(Rank)
           from Ranks
           where AVG(T0.成績) >= Ranks.MinValue
                 and AVG(T0.成績) <= Ranks.MaxValue
           ) AS 平均級別
from 成績表 t0
group by 學(xué)生ID

  這里表面上使用了不等連接,再仔細(xì)想想,Ranks 表中每條記錄的區(qū)間是沒有交集的,
  其實也可以認(rèn)為是等值連接,這樣的表設(shè)計無疑存在著良好的擴(kuò)展性,如果題目只要求

  列印(學(xué)生ID,學(xué)生姓名,有效課程數(shù),有效平均分,平均分級別):

  select 學(xué)生ID,MAX(學(xué)生姓名) as 學(xué)生姓名,count(*),avg(t0.成績)
         ,(SELECT max(Rank)
             from Ranks
            where AVG(T0.成績) >= Ranks.MinValue
                  and AVG(T0.成績) <= Ranks.MaxValue
           ) AS 平均級別
from T as T0
group by 學(xué)生ID

  則這樣的解決方案就比較全面了。

  回到原題,再介紹一個比較取巧的辦法,僅需一個簡單分組查詢就可解決問題,有經(jīng)驗的讀者可能已經(jīng)想到了
  ,那就是 CASE:

  SELECT 學(xué)生ID, MIN(學(xué)生姓名),
         SUM(CASE 課程ID WHEN ‘K1‘ THEN 成績 ELSE 0 END) AS 數(shù)學(xué),
         SUM(CASE 課程ID WHEN ‘K2‘ THEN 成績 ELSE 0 END) AS 語文,
         SUM(CASE 課程ID WHEN ‘K3‘ THEN 成績 ELSE 0 END) AS 英語,
         SUM(CASE 課程ID WHEN ‘K4‘ THEN 成績 ELSE 0 END) AS 政治,
         COUNT(*) AS 有效課程數(shù), AVG(T.成績) AS 平均成績
    FROM 成績表 AS T
GROUP BY 學(xué)生ID
ORDER BY 平均成績 DESC

  雖然可能初看答案感覺有點怪,其實很好理解,可讀性并不低,效率也很高。但它不能
  像前一個答案那樣,在成績中區(qū)分出某一門課這個學(xué)生究竟是缺考 (NULL),還是真得
  零分。這個解法充分利用了 CASE 語句進(jìn)行數(shù)據(jù)分類的作用: CASE 將成績按課程分
  成四類,SUM 用來消去多余的 0。

  SELECT [T].[學(xué)生ID],MAX([T].[學(xué)生姓名]) AS 學(xué)生姓名,
         MAX([T1].[成績]) AS 數(shù)學(xué),
  MAX([T2].[成績]) AS 語文,
  MAX([T3].[成績]) AS 英語,
  MAX([T4].[成績]) AS 政治,
  COUNT([T].[課程ID]) AS 有效課程數(shù),
         (ISNULL(MAX([T1].[成績]),0) +
   ISNULL(MAX([T2].[成績]),0) +
   ISNULL(MAX([T3].[成績]),0) +
   ISNULL(MAX([T4].[成績]),0)) / COUNT([T].[課程ID]) AS 有效平均分
    FROM 成績表 T
         LEFT JOIN 成績表 AS [T1]  ON [T].[學(xué)生ID] = [T1].[學(xué)生ID] AND [T1].[課程ID] = ‘K1‘
         LEFT JOIN 成績表 AS [T2]  ON [T].[學(xué)生ID] = [T2].[學(xué)生ID] AND [T2].[課程ID] = ‘K2‘
         LEFT JOIN 成績表 AS [T3]  ON [T].[學(xué)生ID] = [T3].[學(xué)生ID] AND [T3].[課程ID] = ‘K3‘
         LEFT JOIN 成績表 AS [T4]  ON [T].[學(xué)生ID] = [T4].[學(xué)生ID] AND [T4].[課程ID] = ‘K4‘
GROUP BY [T].[學(xué)生ID]
ORDER BY 有效平均分 DESC

  這個方法是相當(dāng)正統(tǒng)的聯(lián)接解法,盡管寫起來麻煩了些,但還是不難理解的。再從實用
  角度考慮一下,真實需求往往不是象本題明確提出"列印四門 (數(shù)學(xué),語文,英語,政治)
  課程"這樣的相對靜態(tài)的需求,該是動態(tài) SQL 大顯身手的時候了,很明顯方法一的寫法
  無疑是利用程序構(gòu)造動態(tài) SQL 的最好選擇,當(dāng)然另兩個 SQL 規(guī)律還是挺明顯的,同樣
  不難構(gòu)造。以 CASE 版答案為例: 先用一個游標(biāo)遍歷,取出所有課程湊成:
  SUM(CASE ‘課程ID‘ WHEN ‘課程名稱‘ THEN 成績 ELSE 0 END) AS 課程名稱 形式,
  再補上 SELECT 和 FROM、WHERE 等必要條件,一個生成動態(tài)成績單的 SQL 就誕生了,
  只要再由相關(guān)程序調(diào)用執(zhí)行即可,這樣就可以算一個更完善的解決方案了。

  其實,最類似的典型應(yīng)用是在主、細(xì)關(guān)系中的主表投影中實現(xiàn)細(xì)表的匯總統(tǒng)計行,
  例如兩張表:
   Master(F,f1,f2 ...) 一對多 Details(F,f3,f4 ...) 
  SELECT *
         ,( SELECT COUNT(*)
              FROM Details
             WHERE Master.F = Details.F
          )
         ,( SELECT SUM(F3)
              FROM Details
             WHERE Master.F = Details.F
          )
    FROM Master

4.按各科不平均成績從低到高和及格率的百分?jǐn)?shù)從高到低順序,統(tǒng)計并列印各科平均成績和不及格率的百分?jǐn)?shù)(用"N行"表示):
(就是分析哪門課程難)
  課程ID,課程名稱,平均成績,及格百分比
  SELECT 課程ID,MAX(課程名稱) AS 課程名稱,AVG(成績) AS 平均成績
         ,str(100 * SUM(CASE WHEN 成績 >=60 THEN 1 ELSE 0 END)/COUNT(*))+‘%‘ AS 及格百分比
    FROM 成績表 T
GROUP BY 課程ID
ORDER BY 及格百分比 DESC

  這道題應(yīng)該說是算簡單的了,就是用"行"來提供表現(xiàn)形式的。只要想明白要對數(shù)據(jù)如
  何分組,取統(tǒng)計聚集函數(shù),就萬事大吉了。

5.列印四門課程平均成績和及格率的百分?jǐn)?shù)(用"1行4列"表示): (就是分析哪門課程難)
  數(shù)學(xué)平均分,數(shù)學(xué)及格百分?jǐn)?shù),語文平均分,語文及格百分?jǐn)?shù),英語平均分,英語及格百分?jǐn)?shù),政治平均分,政治及格百分?jǐn)?shù)

  這道題其實就是上一題的"列"表現(xiàn)形式版本,相對于上一題,本題是靜態(tài)的,因為本題
  同第三題一樣利用行上的數(shù)據(jù)構(gòu)造了列,要實現(xiàn)擴(kuò)展必須再利用另外的程序構(gòu)造動態(tài)
  SQL:

  SELECT SUM(CASE WHEN 課程ID = ‘K1‘ THEN 成績 ELSE 0 END)/SUM(CASE 課程ID WHEN ‘K1‘ THEN 1 ELSE 0 END) AS 數(shù)學(xué)平均分
         ,100 * SUM(CASE WHEN 課程ID = ‘K1‘ AND 成績 >= 60 THEN 1 ELSE 0 END)/SUM(CASE WHEN 課程ID = ‘K1‘ THEN 1 ELSE 0 END) AS 數(shù)學(xué)及格百分?jǐn)?shù)
         ,SUM(CASE WHEN 課程ID = ‘K2‘ THEN 成績 ELSE 0 END)/SUM(CASE 課程ID WHEN ‘K2‘ THEN 1 ELSE 0 END) AS 語文平均分
         ,100 * SUM(CASE WHEN 課程ID = ‘K2‘ AND 成績 >= 60 THEN 1 ELSE 0 END)/SUM(CASE WHEN 課程ID = ‘K2‘ THEN 1 ELSE 0 END) AS 語文及格百分?jǐn)?shù)
         ,SUM(CASE WHEN 課程ID = ‘K3‘ THEN 成績 ELSE 0 END)/SUM(CASE 課程ID WHEN ‘K3‘ THEN 1 ELSE 0 END) AS 英語平均分
         ,100 * SUM(CASE WHEN 課程ID = ‘K3‘ AND 成績 >= 60 THEN 1 ELSE 0 END)/SUM(CASE WHEN 課程ID = ‘K3‘ THEN 1 ELSE 0 END) AS 英語及格百分?jǐn)?shù)
         ,SUM(CASE WHEN 課程ID = ‘K4‘ THEN 成績 ELSE 0 END)/SUM(CASE 課程ID WHEN ‘K4‘ THEN 1 ELSE 0 END) AS 政治平均分
         ,100 * SUM(CASE WHEN 課程ID = ‘K4‘ AND 成績 >= 60 THEN 1 ELSE 0 END)/SUM(CASE WHEN 課程ID = ‘K4‘ THEN 1 ELSE 0 END) AS 政治及格百分?jǐn)?shù)
   FROM 成績表 T

  這一句看起來很長,但實際上是最經(jīng)典的 CASE 運用,很實用的數(shù)據(jù)分析技術(shù)。先將原
  表中的成績一列連續(xù)投影 8 次備用于四門不同課程,充分利用 CASE 和數(shù)據(jù)的值域
  [‘k1‘,‘k2‘,‘k3‘,‘k4‘]來劃分?jǐn)?shù)據(jù),再利用 SUM() [1 + ...+ 1] 實現(xiàn)了看似本來應(yīng)
  該用 COUNT(*) 的計數(shù)器的功能,這里面不要說聯(lián)接和子查詢,甚至連 Group by 分組
  的痕跡都找不到!如果讀起來吃力,完全可以先只保留一個字段,相對好理解些,看懂后
  逐一補全。本題也可以算一個"行變列"的交叉透視表示例吧! 另外,"行"相對于"列"
  是動態(tài)的,"行"是相對無限的,"列"是相對有限的,"行"的增刪是應(yīng)用級的,可"隨意"增
  刪,"列"的增刪是管理級的,不要輕易變動!

6.按不同老師所教不同課程平均分從高到低列印: (就是分析哪個老師的哪個課程水平高)
  教師ID,教師姓名,課程ID,課程名稱,平均分

  SELECT 教師ID,MAX(教師姓名) AS 教師姓名,課程ID,MAX(課程名稱) AS 課程名稱,AVG(成績) AS 平均成績
    FROM 成績表 T
GROUP BY 課程ID,教師ID
ORDER BY AVG(成績) DESC

  這道題的確沒啥好說的,就算閉著眼,不動手,答案也應(yīng)脫口而出!
  如果平均分按去掉一個最高分和一個最低分后取得,則也不難寫出:

  SELECT 教師ID,MAX(教師姓名),課程ID,MAX(課程名稱) AS 課程名稱 --,AVG(成績) AS 平均成績
         ,(SUM(成績)
           -(SELECT MAX(成績)
               FROM 成績表
              WHERE 課程ID= T1.課程ID AND 教師ID = T1.教師ID)
           -(SELECT MIN(成績)
               FROM 成績表
              WHERE 課程ID= T1.課程ID and 教師ID = T1.教師ID))
          / CAST((SELECT COUNT(*) -2
                    FROM 成績表
                   WHERE 課程ID= T1.課程ID AND 教師ID = T1.教師ID) AS FLOAT) AS 平均分
FROM 成績表 AS T1
WHERE (SELECT COUNT(*) -2
         FROM 成績表
        WHERE 課程ID = T1.課程ID AND 教師ID = T1.教師ID) >0
GROUP BY 課程ID,教師ID
ORDER BY 平均分 DESC
********************************************************************************************
7.列印數(shù)學(xué)成績第 10 名到第 15 名的學(xué)生成績單
  或列印平均成績第 10 名到第 15 名的學(xué)生成績單
  [學(xué)生ID],[學(xué)生姓名],數(shù)學(xué),語文,英語,政治,平均成績

  如果只考慮一門課程,如:數(shù)學(xué)成績,非常簡單:
  select Top 5 *
   from T
  where 課程id =‘K1‘
        and 成績 not in(select top 15 成績
                          from T
                      order by 成績 desc
                       )
order by 成績 desc
union
  select *
    from T
   where 課程id =‘K1‘
         and 成績 not in(select top 10 成績
                           from T
                       order by 成績 desc
                         )
         and 成績 in(select top 15 成績
                       from T
                   order by 成績 desc
                    )
order by 成績 desc

  從邏輯上說,第 10 名到第 15 名就是從原前 15 名,"再"挑出前 5 名不要,保留剩下
  的 5 名。第二種寫法是從前 15 名里挑出不屬于原前 10 名的記錄,把兩個數(shù)據(jù)集做
  一個差,因此要多用一個
  子查詢,效率相對較低,它,如果要有《ANSI/ISO SQL》的 EXCEPT
  關(guān)鍵字就是最理想的了。

  這種技巧在數(shù)據(jù)"分頁"的應(yīng)用中經(jīng)常利用,只要遵循如下原則即可:

   SELECT Top @PageSize *
     FROM T
    WHERE SortField NOT IN (SELECT TOP @PageSize * @Pagei SortField
                              FROM T
                          ORDER BY SortField
                            )
 ORDER BY SortField

  至此,該題考察的主要目的已經(jīng)達(dá)到。至于列印明晰成績單:
  [學(xué)生ID],[學(xué)生姓名],數(shù)學(xué),語文,英語,政治,平均成績 前面也有類似的題目,做起來
  確實麻煩,因此下面僅提供參考答案,就不贅述了:

  SELECT  DISTINCT top 5
       [成績表].[學(xué)生ID],
       [成績表].[學(xué)生姓名] AS 學(xué)生姓名,
       [T1].[成績] AS 數(shù)學(xué),
       [T2].[成績] AS 語文,
       [T3].[成績] AS 英語,
       [T4].[成績] AS 政治,
       ISNULL([T1].[成績],0) + ISNULL([T2].[成績],0) + ISNULL([T3].[成績],0) + ISNULL([T4].[成績],0) as 總分
   FROM [成績表]
             LEFT JOIN [成績表] AS [T1]
                       ON [成績表].[學(xué)生ID] = [T1].[學(xué)生ID] AND [T1].[課程ID] = ‘k1‘
             LEFT JOIN [成績表] AS [T2]
                       ON [成績表].[學(xué)生ID] = [T2].[學(xué)生ID] AND [T2].[課程ID] = ‘k2‘
             LEFT JOIN [成績表] AS [T3]
                       ON [成績表].[學(xué)生ID] = [T3].[學(xué)生ID] AND [T3].[課程ID] = ‘k3‘
             LEFT JOIN [成績表] AS [T4]
                       ON [成績表].[學(xué)生ID] = [T4].[學(xué)生ID] AND [T4].[課程ID] = ‘k4‘
WHERE ISNULL([T1].[成績],0) + ISNULL([T2].[成績],0) + ISNULL([T3].[成績],0) + ISNULL([T4].[成績],0)
      NOT IN
      (SELECT
             DISTINCT
             TOP 15 WITH TIES
             ISNULL([T1].[成績],0) + ISNULL([T2].[成績],0) + ISNULL([T3].[成績],0) + ISNULL([T4].[成績],0)
       FROM [成績表]
            LEFT JOIN [成績表] AS [T1]
                      ON [成績表].[學(xué)生ID] = [T1].[學(xué)生ID] AND [T1].[課程ID] = ‘k1‘
            LEFT JOIN [成績表] AS [T2]
                      ON [成績表].[學(xué)生ID] = [T2].[學(xué)生ID] AND [T2].[課程ID] = ‘k2‘
            LEFT JOIN [成績表] AS [T3]
                      ON [成績表].[學(xué)生ID] = [T3].[學(xué)生ID] AND [T3].[課程ID] = ‘k3‘
            LEFT JOIN [成績表] AS [T4]
                      ON [成績表].[學(xué)生ID] = [T4].[學(xué)生ID] AND [T4].[課程ID] = ‘k4‘
       ORDER BY ISNULL([T1].[成績],0) + ISNULL([T2].[成績],0) + ISNULL([T3].[成績],0) + ISNULL([T4].[成績],0) DESC)

  最后還要多說一句: 一般 TOP 關(guān)鍵字與 ORDER BY 子句合用才有真正意義。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多