1. 程式人生 > >mysql中的EXISTS用法,詳細講解

mysql中的EXISTS用法,詳細講解

首先頭腦中有三點概念:

    1 。  EXISTS子查詢找到的提交

            NOT EXISTS 子查詢中 找不到的提交

           說明:不要去翻譯為存在和不存在,把腦袋搞暈。

  2 。 建立程式迴圈的概念,這是一個動態的查詢過程。如 FOR迴圈 。

  3 。 Exists執行的流程Exists首先執行外層查詢,再執行記憶體查詢,與IN相反。 流程為首先取出外

層中的第       一  元組, 再執行內層查詢,將外層表的第一元組代入,若內層查詢為真,即有結果

時。返回外層表中的第一元組,接著取出第二元組,執行相同的演算法。一直到掃描完外層整表 。

         for(int i =0;  i<>EOFout;i++)

                 {

                     for (int j = 0 ; j<EOFint,j++)

                }

然後再來看一個例子:三張表  學生表student (Sno,Sname), 課程表course (Cno,Cname)選課表SC

(Sno,Cno)

要求查詢出 :選修了全部課程的學生姓名

我的思路:

首先學生的選課資訊存在於SC表中, 要想知道某個學生是否選修了全部課程,至少我們需要知道一共有

幾門課程,這是首要的條件。其次,學生選修了與否,我們又要掃描SC全表,統計出選修了所有課程的

學生號,最後在STUDENT表中根據學生號打出姓名 。

語句如下:  (已測試)

select Sname from student             

 where Sno IN

   (select Sno from SC

   group by Sno //根據Sno分組,統計每個學生選修了幾門課程。如果等於course的總數,就是我們要找的Sno

     having count(*) = (select count(*) from course ))    //統計course中共有幾門課程

另一種思路:

引入:將題目換為查詢學號為 00003 沒有選修的科目  

        思路:我們可以將已知學號代入,把每一個科目代入(迴圈),這將形成1*count(*)種組合。

將這組成作為條件,一一與SC表種進行比對,找不到匹配的我們提交 。

                 select Cname from course  where

                          not exists               //找不到的組合,提交course

                               (select * from SC where course.cno = cno and sno = ''00002'')

//在SC中匹配

換個題目: 查詢沒有 沒有選修科目的學生姓名

         思路:學號未知 , 科目未知,說明有兩個未知變數。應該有兩個EXISTS。我們可以掃描

student 和 course共有 s * c 中組合,將這些組合與SC的每一項進行匹配,注意s*c組合已經包含所

有可能。如果全部找到,就說明已經選修了全部課程。找不到就說明有課程沒選修 。再將沒選修的的

提交給上一exists迴圈 。若上一exists不存在的再提交給外迴圈。

                        select Sname from student

                           where NOT exists        //

                              (select  * from course

                               where NOT exists      //不存在的提交給course

                                (select * from SC where

                                    Sno = student.sno  and cno = Course.Cno))   //代入兩個未知變數

回頭看,就是我們第一個引出的題目:

           選修了全部課程的學生姓名

首先頭腦中有三點概念:

    1 。 EXISTS 子查詢找到的提交

            NOT EXISTS 子查詢中 找不到的提交

           說明:不要去翻譯為存在和不存在,把腦袋搞暈。

2 。 建立程式迴圈的概念,這是一個動態的查詢過程。如FOR迴圈 。

3 。 Exists執行的流程Exists首先執行外層查詢,再執行記憶體查詢,與IN相反。 流程為首先取出外

層中的第一元組,再執行內層查詢,將外層表的第一元組代入,若內層查詢為真,即有結果

時。返回外層表中的第一元組,接著取出第二元組,執行相同的演算法。一直到掃描完外層整表 。

         for(int i =0; i<>EOFout;i++)

                 {

                     for (int j = 0 ; j<EOFin,j++)

                }

然後再來看一個例子:三張表 學生表student (Sno,Sname),課程表course (Cno,Cname)選課表SC

(Sno,Cno)

要求查詢出:選修了全部課程的學生姓名

我的思路:

首先學生的選課資訊存在於SC表中, 要想知道某個學生是否選修了全部課程,至少我們需要知道一共有

幾門課程,這是首要的條件。其次,學生選修了與否,我們又要掃描SC全表,統計出選修了所有課程的

學生號,最後在STUDENT表中根據學生號打出姓名 。

語句如下: (已測試)

select Sname from student             

where Sno IN

   (select Sno from SC

   group by Sno //根據Sno分組,統計每個學生選修了幾門課程。如果等於course的總數,就是我們要找的Sno

     having count(*) = (select count(*) from course ))    //統計course中共有幾門課程

另一種思路:

引入:將題目換為查詢學號為 00003 沒有選修的科目  

        思路:我們可以將已知學號代入,把每一個科目代入(迴圈),這將形成1*count(*)種組合。

將這組成作為條件,一一與SC表種進行比對,找不到匹配的我們提交 。

                 select Cname from course where

                          not exists               //找不到的組合,提交course

                               (select * from SC where course.cno = cno and sno = ''00003'')

//在SC中匹配

換個題目:查詢沒有 沒有選修科目的學生姓名

         思路:學號未知 , 科目未知,說明有兩個未知變數。應該有兩個EXISTS。我們可以掃描

student 和 course共有 s * c 中組合,將這些組合與SC的每一項進行匹配,注意s*c組合已經包含所

有可能。如果全部找到,就說明已經選修了全部課程。找不到就說明有課程沒選修 。再將沒選修的的
提交給上一exists迴圈 。若上一exists不存在的再提交給外迴圈。



最後詳細回答你的問題:資料庫SQL語句中 查詢選修了全部課程的學生的學號和姓名 
查詢選修了全部課程的學生姓名。
        SELECT Sname
         FROM Student
         WHERE NOT EXISTS
            (SELECT *
              FROM Course
              WHERE NOT EXISTS
                  (SELECT *
                   FROM SC
                   WHERE Sno= Student.Sno
                      AND Cno= Course.Cno);

理解如下:   查詢選修了全部課程的學生姓名。   
不用管怎麼樣,第一個select必定是在 student表裡選 sname既:
     SELECT Sname
         FROM Student
加上條件即: where
條件是什麼呢?條件就是---------------------》 查詢選修了全部課程的
因為沒有   (任意一個)謂詞, 只能用  EXISTS  或者  NOT EXISTS來表示。 這點理解吧?
所以要把條件翻譯成 -----------------------》 不存在一門課程這個學生沒有選修
where後面就是 不存在(NOT EXISTS) (
        一門課程這個學生沒有選修
)

接下來就是把Course表中的課程依次拿出來找出 沒有選修的 
怎麼找呢? 因為  NOT EXISTS子查詢中 找不到的提交
另外你要明白 ----------------------------NOT EXISTS查詢 都是相關查詢----------
所以只要把在最後一個select 中  
                         WHERE Sno= Student.Sno
                                             AND Cno= Course.Cno);
就是將這個同學通過 SC表 和  Crouse的 課程連線一遍,找到連線不上的,即: 沒有選修的, 這樣就找到了一門課這個學生沒有選修, 存在沒有選修的課,那麼該學生被pass掉了,
一次進行一個同學的判斷 。



             若你學過程式程式設計,可以看下面的內容, 若沒有則可忽略、。----------

            上述是理解是資料庫系統內部的實現,可以用for迴圈表示
            for(i=1; i<student.length( 學生的總人數); i++){
                              for(i=j;j<Crouse.length(總的課門數); j++){
                                    條件就是:
                                     沒有一門課沒有選修                                                         
                             }
                     }


   
最後你找記住 
1. 第一個select就是 你要選的就是   學生
    SELECT Sname
         FROM Student
2. 第二個 select 就是 課程
3.  第三個select就是  學生和課程發生關係的表 ------------SC選修表
   讓他們連線起來



固定的模式 1你要的結果的表  學生
           2  滿足條件的表   課程表
           3  產生關係的表   選修表
             where    通過選修表把他們連線起來

============================

查詢select----存在量詞查詢

exists代表存在量詞ョ,該查詢結果沒有值,只有邏輯值真true和邏輯假false兩個值。

ex41:查詢所有選修了001課程的學生名單

select sname
from student a
where exists ( 
select *
from sc b
where a.sno=b.sno and cno='001')

ex42:查詢沒有選修了001課程的學生名單

select sname
from student a
where not exists ( 
select *
from sc b
where a.sno=b.sno and cno='001')

ex43:查詢選修了所有課程的學生名單。

由於SQL中沒有全稱量詞,可以這樣理解:查詢這樣的學生,沒有一門課程他沒有選

select sname
from student a
where not exists ( 
select *
from course b
where not exists (
select *
from sc c
where a.sno=c.sno and c.cno=b.cno))

注意:SQL沒有蘊涵謂詞,可以使用等價變換進行轉換

p→q ≡ ┑p∨q

ex43:查詢至少選修了學生95002選修的全部課程的學生名單。

將查詢進行變換:

p表示的謂詞:95002選修了課程y

q表示的謂詞:學生x選修了課程y

該查詢轉換為:( y)p→q

進一步轉換:( y)p→q ≡

┑(ョy( ┑(p→q))) ≡ ┑(ョy( ┑(┑p∨q)))

≡ ┑ョy(p∧q)德模根定律

它所表達的含義為:不存在這樣的課程y,95002選修了y而x沒有選,SQL語句如下:

select sname,sno
from student a
where sno <> '95002' and not exists ( 
select *
from sc b
where sno='95002' and not exists (
select *
from sc c
where a.sno=c.sno and c.cno=b.cno))