SQL(2)--復(fù)雜查詢

介紹多表查詢等復(fù)雜SQL語(yǔ)句。

關(guān)系數(shù)據(jù)庫(kù)的查詢結(jié)果都是一個(gè)結(jié)果表(也是關(guān)系)

集聚函數(shù)

基本語(yǔ)法

  • 統(tǒng)計(jì)元組個(gè)數(shù)
    • COUNT(*)
  • 統(tǒng)計(jì)一列中值的個(gè)數(shù)
    • COUNT([DISTINCT|ALL]<列名>)
  • 計(jì)算一列值的總和(此列必須為數(shù)值型)
    • SUM([DISTINCT|ALL]<列名>)
  • 計(jì)算一列值的平均值(此列必須為數(shù)值型)
    • AVG([DISTINCT|ALL]<列名>)
  • 求一列中的最大值和最小值
    • MAX([DISTINCT|ALL]<列名>)
    • MIN([DISTINCT|ALL]<列名>)

例子

  • 查詢選修1號(hào)課程的學(xué)生最高分?jǐn)?shù)

    • SELECTMAX(Grade)
         FROM SC
         WHERE Cno='1';
      
  • 查詢學(xué)生201215012選修課程的總學(xué)分?jǐn)?shù)

    • SELECT SUM(Ccredit)
          FROM  SC,Course
          WHERE Sno='201215012'                
          AND SC.Cno=Course.Cno; 
      

GROUP BY 子句

細(xì)化聚集函數(shù)的作用對(duì)象

  • 如果未對(duì)查詢結(jié)果分組,聚集函數(shù)將作用于整個(gè)查詢結(jié)果
  • 對(duì)查詢結(jié)果分組后,聚集函數(shù)將分別作用于每個(gè)組
  • 按指定的一列或多列值分組,值相等的為一組

HAVING短語(yǔ)與WHERE子句的區(qū)別:

  • 作用對(duì)象不同
  • WHERE子句作用于基表或視圖,從中選擇滿足條件的元組
  • HAVING短語(yǔ)作用于組,從中選擇滿足條件的組
  • WHERE子句不能使用聚合函數(shù)!

例子

  1. 求各個(gè)課程號(hào)及相應(yīng)的選課人數(shù)

       SELECT Cno, COUNT(Sno)
       FROM    SC
       GROUP BY Cno; 
    
  2. 查詢選修了3門(mén)以上課程的學(xué)生學(xué)號(hào)

     SELECT Sno
         FROM  SC
         GROUP BY Sno
         HAVING  COUNT(*) >3;      
    
  3. 查詢平均成績(jī)大于等于90分的學(xué)生學(xué)號(hào)和平均成績(jī)

        SELECT  Sno, AVG(Grade)
        FROM  SC
        GROUP BY Sno
        HAVING AVG(Grade)>=90;
    

    這里只能使用HAVING,不能使用WHERE。

ORDER BY子句

  • 可以按一個(gè)或多個(gè)屬性列排序
    • 優(yōu)先級(jí)逐漸降低
  • 升序:ASC;
  • 降序:DESC;
  • 缺省值為升序
  • 對(duì)于空值,排序時(shí)顯示的次序由具體系統(tǒng)實(shí)現(xiàn)來(lái)決定

例子

  1. 查詢選修了3號(hào)課程的學(xué)生的學(xué)號(hào)及其成績(jī),查詢結(jié)果按分?jǐn)?shù)降序排列

        SELECT Sno, Grade
        FROM    SC
        WHERE  Cno= ' 3 '
        ORDER BY Grade DESC;
    
  2. 查詢?nèi)w學(xué)生情況,查詢結(jié)果按所在系的系號(hào)升序排列,同一系中的學(xué)生按年齡降序排列

        SELECT  *
        FROM  Student
        ORDER BY Sdept, Sage DESC;  
    

連接查詢

  • 連接查詢:同時(shí)涉及兩個(gè)以上的表的查詢

  • 連接條件或連接謂詞:用來(lái)連接兩個(gè)表的條件

  • 一般格式:

    [<表名1>.]<列名1> <比較運(yùn)算符> [<表名2>.]<列名2>

    [<表名1>.]<列名1>BETWEEN [<表名2>.]<列名2>AND[<表名2>.]<列名3>

  • 連接字段:連接謂詞中的列名稱

    • 連接條件中的各連接字段類型必須是可比的,但名字不必相同

(非)等值連接查詢

等值連接:連接運(yùn)算符為=,這里與Join操作等價(jià)。

例子

  1. 查詢每個(gè)學(xué)生及其選修課程的情況

        SELECT  Student.*, SC.*
        FROM     Student, SC
        WHERE  Student.Sno = SC.Sno;
    
  2. 一條SQL語(yǔ)句可以同時(shí)完成選擇和連接查詢,這時(shí)WHERE子句是由連接謂詞和選擇謂詞組成的復(fù)合條件。

    查詢選修2號(hào)課程且成績(jī)?cè)?0分以上的所有學(xué)生的學(xué)號(hào)和姓名

        SELECT  Student.Sno, Sname
        FROM     Student, SC
        WHERE  Student.Sno=SC.Sno  AND                          
               SC.Cno=' 2 ' AND SC.Grade>90;
    

執(zhí)行過(guò)程

嵌套循環(huán)法(NESTED-LOOP)

  • 首先在表1中找到第一個(gè)元組,然后從頭開(kāi)始掃描表2,逐一查找滿足連接件的元組,找到后就將表1中的第一個(gè)元組與該元組拼接起來(lái),形成結(jié)果表中一個(gè)元組。
  • 表2全部查找完后,再找表1中第二個(gè)元組,然后再?gòu)念^開(kāi)始掃描表2,逐一查找滿足連接條件的元組,找到后就將表1中的第二個(gè)元組與該元組拼接起來(lái),形成結(jié)果表中一個(gè)元組。
  • 重復(fù)上述操作,直到表1中的全部元組都處理完畢

可以發(fā)現(xiàn),等值連接的復(fù)雜度很高,為O(m* n)。

自身連接

  • 自身連接:一個(gè)表與其自己進(jìn)行連接
  • 需要給表起別名以示區(qū)別
  • 由于所有屬性名都是同名屬性,因此必須使用別名前綴

例子

  1. 查詢每一門(mén)課的間接先修課(即先修課的先修課)

     SELECT  FIRST.Cno, SECOND.Cpno
         FROM  Course  FIRST, Course  SECOND
         WHERE FIRST.Cpno = SECOND.Cno;
    

外連接

外連接與普通連接的區(qū)別

  • 普通連接操作只輸出滿足連接條件的元組
  • 外連接操作以指定表為連接主體,將主體表中不滿足連接條件的元組一并輸出
  • 左外連接
    • 列出左邊關(guān)系中所有的元組
  • 右外連接
    • 列出右邊關(guān)系中所有的元組

例子

    SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade
    FROM  Student  LEFT OUT JOIN SC ON    
                 (Student.Sno=SC.Sno); 
53960143076

多表連接

兩個(gè)以上的表進(jìn)行連接。

MongoDB不提供這種操作:

  • JOIN很慢
  • 多級(jí)擴(kuò)展能力差,代價(jià)太高

例子

  1. 查詢每個(gè)學(xué)生的學(xué)號(hào)、姓名、選修的課程名及成績(jī)

      SELECT Student.Sno, Sname, Cname, Grade
      FROM   Student, SC, Course    /*多表連接*/
      WHERE Student.Sno = SC.Sno 
                   AND SC.Cno = Course.Cno;
    

嵌套查詢

  • 一個(gè)SELECT-FROM-WHERE語(yǔ)句稱為一個(gè)查詢塊

  • 將一個(gè)查詢塊嵌套在另一個(gè)查詢塊的WHERE子句或HAVING短語(yǔ)的條件中的查詢稱為嵌套查詢

  • 上層的查詢塊稱為外層查詢或父查詢

  • 下層查詢塊稱為內(nèi)層查詢或子查詢

  • SQL語(yǔ)言允許多層嵌套查詢

    • 即一個(gè)子查詢中還可以嵌套其他子查詢
  • 子查詢的限制

    • 不能使用ORDERBY子句
    • 因?yàn)镺RDER BY 結(jié)果為有序的,不滿足關(guān)系的定義,只能作為最后的生成結(jié)果

帶有IN謂詞的子查詢

  1. 查詢與“劉晨”在同一個(gè)系學(xué)習(xí)的學(xué)聲

    SELECT Sno, Sname, Sdept
             FROM Student
             WHERE Sdept  IN
                      (SELECT Sdept
                       FROM Student
                       WHERE Sname= ' 劉晨 ');
    /*用自身連接表示*/
     SELECT  S1.Sno, S1.Sname,S1.Sdept
          FROM     Student S1,Student S2
          WHERE  S1.Sdept = S2.Sdept  AND
               S2.Sname = '劉晨';
    
  2. 查詢選修了課程名為“信息系統(tǒng)”的學(xué)生學(xué)號(hào)和姓名

    SELECT Sno,Sname                
         FROM    Student                         
         WHERE Sno  IN
                 (SELECT Sno                    
                  FROM    SC                         
                  WHERE  Cno IN
                         (SELECT Cno             
                           FROM Course           
                           WHERE Cname= '信息系統(tǒng)' )
                  );
    /*用連接查詢表示*/
    SELECT Sno,Sname
          FROM    Student,SC,Course
          WHERE   Student.Sno = SC.Sno  AND
                  SC.Cno = Course.Cno AND
                  Course.Cname='信息系統(tǒng)';            
    

帶有比較運(yùn)算符的子查詢

  • 當(dāng)能確切知道內(nèi)層查詢返回單值時(shí),可用比較運(yùn)算符(>,<,=,>=,<=,!=或< >)。

  • 由于一個(gè)學(xué)生只可能在一個(gè)系學(xué)習(xí),則可以用 = 代替IN :

        SELECT Sno,Sname,Sdept
        FROM    Student
        WHERE Sdept   =
                       (SELECT Sdept
                        FROM    Student
                        WHERE Sname= '劉晨');
    
  • 注意,用比較運(yùn)算符取嵌套,只能SELECT一個(gè)屬性,且為數(shù)值類型。

  • 不相關(guān)子查詢

    • 子查詢的查詢條件不依賴于父查詢
    • 由里向外逐層處理。即每個(gè)子查詢?cè)谏弦患?jí)查詢處理之前求解,子查詢的結(jié)果用于建立其父查詢的查找條件。
  • 相關(guān)子查詢

    • 子查詢的查詢條件依賴于父查詢
    • 首先取外層查詢中表的第一個(gè)元組,根據(jù)它與內(nèi)層查詢相關(guān)的屬性值處理內(nèi)層查詢,若WHERE子句返回值為真,則取此元組放入結(jié)果表
    • 然后再取外層表的下一個(gè)元組
    • 重復(fù)這一過(guò)程,直至外層表全部檢查完為止

例子

  1. 找出每個(gè)學(xué)生超過(guò)他選修課程平均成績(jī)的課程號(hào)

    SELECT Sno, Cno
        FROM    SC x
        WHERE Grade >= ( SELECT AVG(Grade) 
                         FROM  SC y
                         WHERE y.Sno = x.Sno );
    /*用連接查詢表示*/
    SELECT First.Sno, First.Cno
     FROM SC First JOIN (
         SELECT Sno, AVG(Grade) as A_Grade
            FROM SC
            GROUP BY Sno) SA
            ON First.Sno = SA.Sno
         WHERE First.Grade > SA.A_Grade
    

帶有ANY(SOME)或ALL謂詞的子查詢

使用ANY或ALL謂詞時(shí)必須同時(shí)使用比較運(yùn)算

若子查詢中不是唯一的,使用ANY/ALL可以使用比較運(yùn)算符

語(yǔ)義為:

> ANY 大于子查詢結(jié)果中的某個(gè)值

>ALL 大于子查詢結(jié)果中的所有值

>=ANY 大于等于子查詢結(jié)果中的某個(gè)值

<=ANY 小于等于子查詢結(jié)果中的某個(gè)值

=ANY 等于子查詢結(jié)果中的某個(gè)值

!=(或<>)ALL 不等于子查詢結(jié)果中的任何一個(gè)值

例子

  1. 查詢非計(jì)算機(jī)科學(xué)系中比計(jì)算機(jī)科學(xué)系任意一個(gè)學(xué)生年齡小的學(xué)生姓名和年齡

    SELECT Sname,Sage
        FROM    Student
        WHERE Sage < ANY ( SELECT  Sage
                           FROM    Student
                           WHERE Sdept= ' CS ')
         AND Sdept <> ‘CS ' ;           /*父查詢塊中的條件 */
    
    /*用聚集函數(shù)實(shí)現(xiàn)*/
    
    SELECT Sname,Sage
         FROM   Student
         WHERE Sage < 
                      ( SELECT MAX(Sage)
                         FROM Student
                         WHERE Sdept= 'CS ')
          AND Sdept <> ' CS ';
    
  2. 查詢非計(jì)算機(jī)科學(xué)系中比計(jì)算機(jī)科學(xué)系所有學(xué)生年齡都小的學(xué)生姓名及年齡

    SELECT Sname,Sage
        FROM Student
        WHERE Sage < ALL
                     (SELECT Sage
                       FROM Student
                       WHERE Sdept= ' CS ')
          AND Sdept <> ' CS ’;
    /*用聚集函數(shù)實(shí)現(xiàn)*/
    SELECT Sname,Sage
        FROM Student
        WHERE Sage < 
                   (SELECT MIN(Sage)
                    FROM Student
                    WHERE Sdept= ' CS ')
        AND Sdept <>' CS ';
    

帶有EXISTS謂詞的子查詢

EXISTS謂詞

  • 存在量詞
  • 帶有EXISTS謂詞的子查詢不返回任何數(shù)據(jù),只產(chǎn)生邏輯真值“true”或邏輯假值“false”。
  • 若內(nèi)層查詢結(jié)果非空,則外層的WHERE子句返回真值
  • 若內(nèi)層查詢結(jié)果為空,則外層的WHERE子句返回假值
  • 由EXISTS引出的子查詢,其目標(biāo)列表達(dá)式通常都用* ,因?yàn)閹XISTS的子查詢只返回真值或假值,給出列名無(wú)實(shí)際意義。

例子

  1. 查詢所有選修了1號(hào)課程的學(xué)生姓名。

    思路

    • 本查詢涉及StudentSC關(guān)系
    • Student中依次取每個(gè)元組的Sno值,用此值去檢查SC
    • SC中存在這樣的元組,其Sno值等于此Student.Sno值,并且其Cno=‘1’,則取此Student.Sname送入結(jié)果表
    SELECT Sname
         FROM Student
         WHERE EXISTS
                       (SELECT *
                        FROM SC
                        WHERE Sno=Student.Sno AND Cno= ' 1 ');
    
  2. 查詢沒(méi)有選修1號(hào)課程的學(xué)生姓名。

    SELECT Sname
         FROM     Student
         WHERE NOT EXISTS
                       (SELECT *
                        FROM SC
                        WHERE Sno = Student.Sno AND    Cno='1');
    

難點(diǎn)

  • 不同形式的查詢間的替換

    • 一些帶EXISTS或NOT EXISTS謂詞的子查詢不能被其他形式的子查詢等價(jià)替換

    • 所有帶IN謂詞、比較運(yùn)算符、ANY和ALL謂詞的子查詢都能用帶EXISTS謂詞的子查詢等價(jià)替換

    • 查詢與“劉晨”在同一個(gè)系學(xué)習(xí)的學(xué)生

      • 可以用帶EXISTS謂詞的子查詢替換

      • SELECT Sno,Sname,Sdept
             FROM Student S1
              WHERE EXISTS
                         (SELECT *
                             FROM Student S2
                             WHERE S2.Sdept = S1.Sdept AND
                                   S2.Sname = '劉晨');
        
  • 用EXISTS/NOT EXISTS實(shí)現(xiàn)全稱量詞(難點(diǎn))

    • 查詢選修了全部課程的學(xué)生姓名

      • 不存在一門(mén)課,這個(gè)學(xué)生沒(méi)有選

      • SELECT Sname
                FROM Student
                WHERE NOT EXISTS
                              (SELECT *
                                FROM Course
                                WHERE NOT EXISTS
                                              (SELECT *
                                               FROM SC
                                               WHERE Sno= Student.Sno
                                                     AND Cno= Course.Cno
                                              )
                               );
        
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這會(huì)兒閑著, 所以寫(xiě)幾筆; 說(shuō)到2017, 先定個(gè)小目標(biāo)。 比如換個(gè)發(fā)型, 然而也從來(lái)沒(méi)有過(guò)發(fā)型; 百斤左右的體重...
    XX的Xixi閱讀 133評(píng)論 0 0
  • 總是自信自己人緣好,跟誰(shuí)都能聊得來(lái),可是每當(dāng)自己遇到問(wèn)題,或者心情不好時(shí),翻遍手機(jī),腦海里都想不出一個(gè)可以傾述的對(duì)...
    6fd7152783bc閱讀 425評(píng)論 0 0
  • 感恩祺予提醒我,我們想做某件事家人反對(duì),并不是說(shuō)你要做的那件事有錯(cuò),而是我們過(guò)去也種子過(guò)不了解他人的種子開(kāi)花結(jié)果了...
    騫卉閱讀 264評(píng)論 0 0
  • 梅子不落閱讀 211評(píng)論 0 1

友情鏈接更多精彩內(nèi)容