跟我一起學Oracle 11g【9】----SQL 基礎學習[嵌套查詢]


前言

在前面2個章節,我們比較詳細的介紹了一些SQL語句的基本用法,但是在我們實際的項目開發中,其實很多時候這些基本的用法遠遠不能滿足我們項目的需求,這個時候就需要我們的嵌套查詢。

在SQL語句中,一個select-from-where語句稱為一耳光查詢快。將一個查詢快嵌套在另外一個的where子句或having 短語的條件的查詢稱為嵌套查詢(Nested Query)。

比如,先舉一個簡單的例子:

select Sname  --------------外查詢語句塊------- 
from Student
where Sno in  --------------外查詢語句塊------- 
      (      --------------內查詢語句塊-------     
         select Sno
          From Sc
          where Cno=2
--------------
內查詢語句塊------- );

查詢語句塊分為外查詢語句或叫父查詢以及內查詢或子查詢。

NOTE:SQL語言允許多層嵌套查詢,即一個子查詢中還可以嵌套其他子查詢。需要特別指出的是,子查詢的select語句中不能使用order by字句,order by 只能對最終查詢結果排序。

一。帶有in謂詞的子查詢

在嵌套查詢中,子查詢往往是一個集合,所以謂詞in是嵌套查詢中最經常使用的謂詞。

【例1】查詢與“XiaoHong”在同一個系的學生

OK,我們一步一步的來分解這個查詢步驟:

①確定“XiaoHong”所在的系

select sdept
from student 
where sname='XiaoHong'

得到的結果是:CS。

②查找所有在CS系學習的所有學生

select sno,sname,sdept 
from student 
where sdept='CS';

ok,得到如下結果:

③合並操作。

現在我們只需要把上面的操作合並在一起就好了!

select sno,sname,sdept 
from student 
where sdept in 
(
  select sdept
  from student 
  where sname='XiaoHong'
);

得到的結果也是一樣。

本例中,因為子查詢的查詢條件不依賴於父查詢,所以稱為不相關查詢

當然本例中也還可以有其他解法:自連接方法如下:

select s1.sno,s1.sname,s1.sdept 
from student s1,student s2 
where s1.sdept=s2.sdept and s2.sname='XiaoHong';

可見,一個查詢有很多種方法,當然不同的方法執行的效率可能會有很大的不同。

【例2】查詢選修了課程名為”Math“的學生學號和姓名

看似這一句很短,其實這里有2個子查詢。我們需要先弄清楚里面的關系,然后在來進行解答

思路如下:

1).課程名在course表中才有,所以我們從course表中選出課程名為Math的課程號(Cno)

2).選出課程號之后,在在SC表中,找到課程號所對應的學生號

3).在student表中找出對應的學號和學生名字。

select sno,sname   --第三步,最后從student表中取出數據出來。 
from student 
where sno in
(
     select sno --第二步。。找出SC關系表中的選修了2號課程的學生學號 
     from sc 
     where cno in
           (
               select cno     -- 第一步。。找出course表中的課程名為math的課程號。結果為2.
         from course 
         where cname='Math'
       )
);

結果如下:

代替方法:

select student.sno,sname from 
student,sc,course 
where course.cname='Math' 
and course.cno=sc.cno and sc.sno=student.sno;

結果也是一樣滴。

二。帶有比較運算符的子查詢

帶有比較運算符的子查詢是指父查詢之間用比較運算符進行連接。當用戶能確切知道內存查詢返回的是單值時,可以用>,<,>=,<=,!=,<>等等比較運算符。

【例3】和例1 是一樣的:查詢與“XiaoHong”在同一個系的學生

因為一個學生只可能在一個系學習,也就是說內查詢的結果是一個值,因此可以用“=”代替“in”

如下:

select sno,sname,sdept 
from student 
where sdept =
(
  select sdept
  from student 
  where sname='XiaoHong'
);

這樣 也能得到和例1的結果。

需要注意的是,子查詢一定要跟在比較符之后,下面寫法是錯誤的:

----------------錯誤寫法---------------------
select
sno,sname,sdept from student where (   select sdept   from student   where sname='XiaoHong') =sdept;
----------------錯誤寫法---------------------

【例4】找出每個學生超過他選修課課程平均成績的課程號

這個怎么理解呢?我們先把結果寫出來,然后再來剖析它。

select sno,cno 
from sc x 
where grade>=
(
    select avg(grade) 
    from sc y 
    where y.
    sno=x.sno);

x是Sc表的別名,y也是一樣。內存查詢是求一個學生所有選修課程平均成績,至於是哪個學生的平均成績要看s.sno的值。,而該值是和父查詢有關的,所以這類查詢叫做相關子查詢。

執行過程可能如下:

①從外層查詢中取出SC表中的一行(也就是元組 x),將x的值sno

select avg(Grade) 
from sc y 
where y.sno=1;

得到結果是98.5

②執行內查詢得到的結果是:98.5,所以得到外查詢是:

select sno,cno 
from sc x 
where Grade>=98.5;

得到結果如下:

然后,外層查詢取出下一個元組重復做上面的動作。。。

得到的結果是:

三。帶有any(some)或all謂詞的子查詢

子查詢返回單值可以用比較算術法,但是返回多值時要用any(有些系統用some)或者all謂詞修飾符。而是用any或all謂詞時則必須同時是用比較運算符。
>any 大於子查詢結果中的某個值
<any 小於子查詢結果中的某個值
>all 大於子查詢結果中的所有值
<all 小於子查詢結果中的所有值

>=any大於等於子查詢結果中的某個值
<=any小於等於子查詢結果中的某個值
>=all 大於等於子查詢結果中的所有值
<=all 小於等於子查詢結果中的所有值

=any 等於子查詢結果中的中的某個值
=all 等於子查詢結果中的所有值(通常沒有實際意思)

!=(或<>)any 不等於子查詢結果中的某個值
!=(或<>)all 不等於子查詢結果中的的任何一個值

【例5】查詢其他系中比計算機科學系某一個學生年齡小的學生姓名和年齡

SQL語句如下:

select sname,sage 
from student
where sage < any
(
    select sage 
        from student 
    where sdept='CS'
) and sdept <> 'CS'; -- 注意這是父查詢的條件

數據庫執行執行此查詢的時候,首先處理子查詢,找出CS系中所有學生的年齡,找出一個集合(18,22)。任何處理父查詢,找出所有不是CS系並且年齡小於18或22的學生即可。

本查詢也可以用聚集函數來實現。首先用子查詢查出CS系中最大年齡(22),任何在父查詢中找出所有非CS系並且年齡小於22歲的學生即可。

select sname,sage 
from student
where sage <
(
    select max(sage)
    from student
    where sdept='CS'
) and sdept<>'CS'

也可以得到上面的結構。結果如下:

【例6】查詢其他系中比計算機科學系所有學生年齡都小的學生姓名和年齡

經過上面的分析,這個很簡單,如下

select sname,sage 
from student
where sage <all
(
    select sage
    from student
    where sdept='CS'
) and sdept<> 'CS';


這里需要向大家說聲對不起,剛開始構建數據的時候,沒有構建好,所以這里查詢為空,為了試驗的完整性,我這里修改一下數據結構。

update student set sage=17 where sname='XiaoZhang';

ok,我們現在在執行剛才的操作,可以得到如下結果。

本查詢也可以使用聚集查詢來實現,如下:

select sname,sage
from student
where sage <
(
    select min(sage)
    from student
    where sdept='CS'
) and Sdept !='CS';

事實上,聚集函數實現子查詢通常比直接用all或any的效率更好。對應關系表如下:

  = <>或!= < <= > >=
ANY IN == <Max <=Max >Min >=Min
ALL == NOT IN <Min <=Min <Max <=Max

四。帶有exists謂詞的子查詢

帶有exists謂詞的子查詢不返回任何數據,只產生邏輯真或假,也就是true或false。

【例6】查詢所有選修了1號課程的學生姓名

select sname 
from student
where exists
(
    select *
    from sc
    where Sno=Student.Sno and Cno=1
)

那上面的執行流程是怎么樣的呢?

①從外查詢student表中取出一行數據

②把這條數據的Sno和內查詢Sc表中的Sno進行比較

③若比較結果為真,則把這數據的sname放入一個結果集合中。

④然后再取student表的嚇一條數據,直到取完為止。

使用exists量詞后,若內存結果非空,則外層的where字句返回真值,否則返回假值。

由於exists引出的子查詢,起目標列表達式通常都是“*”,因為帶有exists的子查詢只返回true或false,給出列名無具體意思。

exists謂詞相對應的是not exists。使用not exists后,如果內存查詢結果為空,則外層的where字句返回真值,否則返回假值。

【例7】查詢沒有選修了1號課程的學生姓名

select sname 
from student
where not exists
(
    select *
    from sc
    where Sno=Student.Sno and Cno=1
)

一些帶exists或not exists謂詞的子查詢不能被其他形式的子查詢等價替換,但是其他帶有in謂詞、比較運算符、any、all謂詞的子查詢都能用exists謂詞的子查詢替換。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM