繼續上一篇中的問題
【常用的Select選擇語句】
三、【 Select 語句之 where 子句的使用 】
【原理】
前面已經接觸過WHERE子句的用法,這一節將詳細討論WHERE子句中查詢條件的構成。WHERE子句必須緊跟FROM子句之后,在WHERE子句中,使用一個條件從FROM子句的中間結果中選取行。where子句操作一般包括 比較運算、模式匹配、范圍比較、空值比較 和 子查詢 5種操作
1、【比較運算】
比較運算符用於比較兩個表達式值,MySQL支持的比較運算符有:=(等於)、<(小於)、<=(小於等於)、>(大於)、>=(大於等於)、<=>(相等或都等於空)、<>(不等於)、!=(不等於)。比較運算的語法格式為:
expression { = | < | <= | > | >= | <=> | <> | != } expression
其中expression是除TEXT和BLOB外類型的表達式。
當兩個表達式值均不為空值(NULL)時,除了“<=>”運算符,其他比較運算返回邏輯值TRUE(真)或FALSE(假);而當兩個表達式值中有一個為空值或都為空值時,將返回UNKNOWN。
如: 查詢XSCJ數據庫XS表中學號為081101的學生的情況。
SELECT 姓名,學號,總學分 FROM XS WHERE 學號='081101';
如:查詢XS表中總學分大於50的學生的情況。
SELECT 姓名, 學號, 出生日期, 總學分 FROM XS WHERE 總學分>50;
MySQL有一個特殊的等於運算符“<=>”,當兩個表達式彼此相等或都等於空值時,它的值為TRUE,其中有一個空值或都是非空值但不相等,這個條件就是FALSE。沒有UNKNOWN的情況。
如: 查詢XS表中備注為空的同學的情況。
SELECT 姓名,學號,出生日期,總學分 FROM XS WHERE 備注<=>NULL;
從查詢條件的構成看出,可以將多個判定運算的結果通過邏輯運算符(AND、OR、XOR和NOT)組成更為復雜的查詢條件。
如: 查詢XS表中專業為計算機,性別為女(0)的同學的情況。
SELECT 姓名,學號,性別,總學分 FROM XS WHERE 專業名='計算機' AND 性別=0;
2、【模式匹配】
LIKE運算符用於指出一個字符串是否與指定的字符串相匹配,其運算對象可以是char、varchar、text、datetime等類型的數據,返回邏輯值TRUE或FALSE。LIKE謂詞表達式的格式為:
match_expression [ NOT ] LIKE match_expression [ ESCAPE 'escape_character' ]
使用LIKE進行模式匹配時,常使用特殊符號_和%,可進行模糊查詢。“%”代表0個或多個字符,“_”代表單個字符。
escape_character:轉義字符,escape_character 沒有默認值,且必須為單個字符。當要匹配的字符串中含有與特殊符號(_和%)相同的字符時,此時應通過該字符前的轉義字符指明其為模式串中的一個匹配字符。使用關鍵字ESCAPE可指定轉義符。
由於MySQL默認不區分大小寫,要區分大小寫時需要更換字符集的校對規則。
如:查詢XSCJ數據庫XS表中姓“王”的學生學號、姓名及性別。
SELECT 學號,姓名,性別 FROM XS WHERE 姓名 LIKE '王%';
如:查詢XSCJ數據庫XS表中學號倒數第二個數字為0的學生學號、姓名及專業名。
SELECT 學號,姓名,專業名 FROM XS WHERE 學號 LIKE '%0_';
如果我們想要查找特殊符號中的一個或全部(_和%),我們必須使用一個轉義字符。
如:查詢XS表中名字包含下畫線的學生學號和姓名。
SELECT 學號,姓名 FROM XS WHERE 學號 LIKE '%#_%' ESCAPE '#';
說明:由於沒有學生滿足這個條件,所以這里沒有結果返回。定義了“#”為轉義字符以后,語句中在“#”后面的“_”就失去了它原來特殊的意義。
3、【范圍比較】
用於范圍比較的關鍵字有兩個:BETWEEN和IN。
當要查詢的條件是某個值的范圍時,可以使用BETWEEN關鍵字。BETWEEN關鍵字指出查詢范圍,格式為:
expression [ NOT ] BETWEEN expression1 AND expression2
當不使用NOT時,若表達式expression的值在表達式expression1與expression2之間(包括這兩個值),則返回TRUE,否則返回FALSE;使用NOT時,返回值剛好相反。
注意:expression1的值不能大於expression2的值。
使用IN關鍵字可以指定一個值表,值表中列出所有可能的值,當與值表中的任一個匹配時,即返回TRUE,否則返回FALSE。使用IN關鍵字指定值表的格式為:
expression IN ( expression [,…n])
如: 查詢XSCJ數據庫XS表中不在1989年出生的學生情況。
SELECT 學號, 姓名, 專業名, 出生日期 FROM XS WHERE 出生日期 NOT BETWEEN '1989-1-1' and '1989-12-31';
如:查詢XS表中專業名為“計算機”、“通信工程”或“無線電”的學生的情況。
SELECT * FROM XS WHERE 專業名 IN ('計算機', '通信工程', '無線電');
該語句與下列語句等價:
SELECT * FROM XS WHERE 專業名 ='計算機' OR 專業名 = '通信工程' OR 專業名 = '無線電';
說明:IN關鍵字最主要的作用是表達子查詢。后面會介紹
4、【空值比較】
當需要判定一個表達式的值是否為空值時,使用IS NULL關鍵字,格式為:
expression IS [ NOT ] NULL
當不使用NOT時,若表達式expression的值為空值,返回TRUE,否則返回FALSE;當使用NOT時,結果剛好相反。
如: 查詢XSCJ數據庫中總學分尚不定的學生情況。
SELECT * FROM XS WHERE 總學分 IS NULL;
5、【子查詢】
在查詢條件中,可以使用另一個查詢的結果作為條件的一部分,例如,判定列值是否與某個查詢的結果集中的值相等,作為查詢條件一部分的查詢稱為子查詢。SQL標准允許SELECT多層嵌套使用,用來表示復雜的查詢。子查詢除了可以用在SELECT語句中,還可以用在INSERT、UPDATE及DELETE語句中。子查詢通常與IN、EXIST謂詞及比較運算符結合使用。
(1)IN子查詢
IN子查詢用於進行一個給定值是否在子查詢結果集中的判斷
如: 查找在XSCJ數據庫中選修了課程號為206的課程的學生的姓名、學號。
SELECT 姓名,學號 FROM XS WHERE 學號 IN ( SELECT 學號 FROM XS_KC WHERE 課程號 = '206' );
注意:IN子查詢只能返回一列數據。對於較復雜的查詢,可以使用嵌套的子查詢。
如:查找未選修離散數學的學生的姓名、學號、專業名。
SELECT 姓名,學號,專業名 FROM XS WHERE 學號 NOT IN ( SELECT 學號 FROM XS_KC WHERE 課程號 IN ( SELECT 課程號 FROM KC WHERE 課程名 ='離散數學' ) );
(2)比較子查詢
這種子查詢可以認為是IN子查詢的擴展,它使表達式的值與子查詢的結果進行比較運算,格式為:
expression { < | <= | = | > | >= | != | <> } { ALL | SOME | ANY } ( subquery )
其中,expression為要進行比較的表達式,subquery是子查詢。ALL、SOME和ANY說明對比較運算的限制。
如果子查詢的結果集只返回一行數據時,可以通過比較運算符直接比較。
ALL指定表達式要與子查詢結果集中的每個值都進行比較,當表達式與每個值都滿足比較的關系時,才返回TRUE,否則返回FALSE;
SOME或ANY是同義詞,表示表達式只要與子查詢結果集中的某個值滿足比較的關系時,就返回TRUE,否則返回FALSE。
如:查找選修了離散數學的學生學號。
SELECT 學號 FROM XS_KC WHERE 課程號 = ( SELECT 課程號 FROM KC WHERE 課程名 ='離散數學' );
如:查找XS表中比所有計算機系的學生年齡都大的學生學號、姓名、專業名、出生日期。
SELECT 學號, 姓名, 專業名, 出生日期 FROM XS WHERE 出生日期 <ALL ( SELECT 出生日期 FROM XS WHERE 專業名 ='計算機' );
如:查找XS_KC表中課程號206的成績不低於課程號101的最低成績的學生的學號。
SELECT 學號 FROM XS_KC WHERE 課程號 = '206' AND 成績 >=ANY ( SELECT 成績 FROM XS_KC WHERE 課程號 ='101' );
(3)EXISTS子查詢
格式為:
[ NOT ] EXISTS ( subquery )
我們通過舉例來說明Exists子查詢的使用方法,如:查找選修206號課程的學生姓名。
SELECT 姓名 FROM XS WHERE EXISTS ( SELECT * FROM XS_KC WHERE 學號 = XS.學號 AND 課程號 = '206' );
分析:
① 本例在子查詢的條件中使用了限定形式的列名引用XS.學號,表示這里的學號列出自表XS。
② 本例與前面的子查詢例子不同點是,前面的例子中,內層查詢只處理一次,得到一個結果集,再依次處理外層查詢;而本例的內層查詢要處理多次,因為內層查詢與XS.學號有關,外層查詢中XS表的不同行有不同的學號值。這類子查詢稱為相關子查詢,因為子查詢的條件依賴於外層查詢中的某些值。其處理過程是:首先查找外層查詢中XS表的第一行,根據該行的學號列值處理內層查詢,若結果不為空,則WHERE條件就為真,就把該行的姓名值取出作為結果集的一行;然后再找XS表的第2、3、…行,重復上述處理過程直到XS表的所有行都查找完為止。
③需要注意的一個問題是:上面的Exists子查詢使用的是select * ,但是Exists子查詢實際上並不管子查詢中要選擇那些列,也就是說select 后面使用 * 還是某些具體的列名,是沒有關系的,一般我們使用 *
對於這種Exists單層的子查詢來收是非常的簡單的,但是Exists的多層嵌套卻非常的復雜,從邏輯上不容易搞清楚,所以我們就不再多說了,遇到了問題之后再研究
子查詢的其他分類依據
1、返回一個表的子查詢是表子查詢;
2、返回帶有一個或多個值的一行的子查詢是行子查詢;
3、返回一行或多行,但每行上只有一個值的是列子查詢;
4、只返回一個值的是標量子查詢。
5、從定義上講,每個標量子查詢都是一個列子查詢和行子查詢
子查詢還可以用在SELECT語句的其他子句中
(1)表子查詢可以用在FROM子句中,但必須為子查詢產生的中間表定義一個別名
如: 從XS表中查找總學分大於50的男同學的姓名和學號。
SELECT 姓名,學號,總學分 FROM ( SELECT 姓名,學號,性別,總學分 FROM XS WHERE 總學分>50 ) AS STUDENT WHERE 性別='1';
說明:在這個例子中,首先處理FROM子句中的子查詢,將結果放到一個中間表中,並為表定義一個名稱STUDENT,然后再根據外部查詢條件從STUDENT表中查詢出數據。另外,子查詢還可以嵌套使用。
(2)SELECT關鍵字后面也可以定義子查詢。
如:從XS表中查找所有女學生的姓名、學號,以及與081101號學生的年齡差距。
SELECT 學號, 姓名, YEAR(出生日期)-YEAR( ( SELECT 出生日期 FROM XS WHERE 學號='081101' ) ) AS 年齡差距 FROM XS WHERE 性別='0';
說明:本例中子查詢返回值中只有一個值,所以這是一個標量子查詢。YEAR函數用於取出DATE類型數據的年份。
(3)在WHERE子句中還可以將一行數據與行子查詢中的結果通過比較運算符進行比較。
如:查找與081101號學生性別相同、總學分相同的學生學號和姓名。
SELECT 學號,姓名 FROM XS WHERE (性別,總學分)=( SELECT 性別,總學分 FROM XS WHERE 學號='081101' );