定義:
子查詢(xún)?cè)试S把一個(gè)查詢(xún)嵌套在另一個(gè)查詢(xún)當(dāng)中。
子查詢(xún),又叫內(nèi)部查詢(xún),相對(duì)于內(nèi)部查詢(xún),包含內(nèi)部查詢(xún)的就稱(chēng)為外部查詢(xún)。
子查詢(xún)可以包含普通select可以包括的任何子句,比如:distinct、 group by、order by、limit、join和union等;但是對(duì)應(yīng)的外部查詢(xún)必須是以下語(yǔ)句之一:select、insert、update、delete、set或 者do。
子查詢(xún)的位置:select 中、from 后、where 中.group by 和order by 中無(wú)實(shí)用意義。
子查詢(xún)分為如下幾類(lèi):
1. 標(biāo)量子查詢(xún):返回單一值的標(biāo)量,最簡(jiǎn)單的形式。
2. 列子查詢(xún):返回的結(jié)果集是 N 行一列。
3. 行子查詢(xún):返回的結(jié)果集是一行 N 列。
4. 表子查詢(xún):返回的結(jié)果集是 N 行 N 列。
可以使用的操作符:= > >= = > ANY IN SOME ALL EXISTS
一個(gè)子查詢(xún)會(huì)返回一個(gè)標(biāo)量(就一個(gè)值)、一個(gè)行、一個(gè)列或一個(gè)表,這些子查詢(xún)稱(chēng)之為標(biāo)量、行、列和表子查詢(xún)。
如果子查詢(xún)返回一個(gè)標(biāo)量值(就一個(gè)值),那么外部查詢(xún)就可以使用:=、>、、>=、=和>符號(hào)進(jìn)行比較判斷;如果子查詢(xún)返回的不是一個(gè)標(biāo)量值,而外部查詢(xún)使用了比較符和子查詢(xún)的結(jié)果進(jìn)行了比較,那么就會(huì)拋出異常。
是指子查詢(xún)返回的是單一值的標(biāo)量,如一個(gè)數(shù)字或一個(gè)字符串,也是子查詢(xún)中最簡(jiǎn)單的返回形式。 可以使用 = > >= = > 這些操作符對(duì)子查詢(xún)的標(biāo)量結(jié)果進(jìn)行比較,通常子查詢(xún)的位置在比較式的右側(cè)
示例:
SELECT * FROM article WHERE uid = (SELECT uid FROM user WHERE status=1 ORDER BY uid DESC LIMIT 1) SELECT * FROM t1 WHERE column1 = (SELECT MAX(column2) FROM t2) SELECT * FROM article AS t WHERE 2 = (SELECT COUNT(*) FROM article WHERE article.uid = t.uid)
指子查詢(xún)返回的結(jié)果集是 N 行一列,該結(jié)果通常來(lái)自對(duì)表的某個(gè)字段查詢(xún)返回。
可以使用 = > >= = > 這些操作符對(duì)子查詢(xún)的標(biāo)量結(jié)果進(jìn)行比較,通常子查詢(xún)的位置在比較式的右側(cè)
可以使用 IN、ANY、SOME 和 ALL 操作符,不能直接使用 = > >= = > 這些比較標(biāo)量結(jié)果的操作符。
示例:
SELECT * FROM article WHERE uid IN(SELECT uid FROM user WHERE status=1) SELECT s1 FROM table1 WHERE s1 > ANY (SELECT s2 FROM table2) SELECT s1 FROM table1 WHERE s1 > ALL (SELECT s2 FROM table2)
NOT IN 是 > ALL 的別名,二者相同。
特殊情況
注意:對(duì)于 table2 空表的情況,下面的語(yǔ)句均返回 NULL:
SELECT s1 FROM table1 WHERE s1 > (SELECT s2 FROM table2) SELECT s1 FROM table1 WHERE s1 > ALL (SELECT MAX(s1) FROM table2)
指子查詢(xún)返回的結(jié)果集是一行 N 列,該子查詢(xún)的結(jié)果通常是對(duì)表的某行數(shù)據(jù)進(jìn)行查詢(xún)而返回的結(jié)果集。
例子:
SELECT * FROM table1 WHERE (1,2) = (SELECT column1, column2 FROM table2) 注:(1,2) 等同于 row(1,2) SELECT * FROM article WHERE (title,content,uid) = (SELECT title,content,uid FROM blog WHERE bid=2)
指子查詢(xún)返回的結(jié)果集是 N 行 N 列的一個(gè)表數(shù)據(jù)。
例子:
SELECT * FROM article WHERE (title,content,uid) IN (SELECT title,content,uid FROM blog)
any關(guān)鍵詞的意思是“對(duì)于子查詢(xún)返回的列中的任何一個(gè)數(shù)值,如果比較結(jié)果為T(mén)RUE,就返回TRUE”。
好比“10 >any(11, 20, 2, 30)”,由于10>2,所以,該該判斷會(huì)返回TRUE;只要10與集合中的任意一個(gè)進(jìn)行比較,得到TRUE時(shí),就會(huì)返回TRUE?!?/p>
select table1.customer_id,city,count(order_id) from table1join table2 on table1.customer_id=table2.customer_id where table1.customer_id>'tx' and table1.customer_id>'9you' group by customer_id having count(order_id) > any ( select count(order_id) from table2 where customer_id='tx' or customer_id='9you' group by customer_id);
any的意思比較好明白,直譯就是任意一個(gè),只要條件滿(mǎn)足任意的一個(gè),就返回TRUE。
使用in進(jìn)行子查詢(xún),這個(gè)我們?cè)谌粘?xiě)sql的時(shí)候是經(jīng)常遇到的。in的意思就是指定的一個(gè)值是否在這個(gè)集合中,如何在就返回TRUE;否則就返回FALSE了。
in是“=any”的別名,在使用“=any”的地方,我們都可以使用“in”來(lái)進(jìn)行替換。
有了in,肯定就有了not in;not in并不是和>any是同樣的意思,not in和>all是一個(gè)意思。
some是any的別名,用的比較少。
all必須與比較操作符一起使用。all的意思是“對(duì)于子查詢(xún)返回的列中的所有值,如果比較結(jié)果為T(mén)RUE,則返回TRUE”。
好比“10 >all(2, 4, 5, 1)”,由于10大于集合中的所有值,所以這條判斷就返回TRUE;而如果為“10 >all(20, 3, 2, 1, 4)”,這樣的話(huà),由于10小于20,所以該判斷就會(huì)返回FALSE。
>all的同義詞是not in,表示不等于集合中的所有值,這個(gè)很容易和>any搞混,平時(shí)多留點(diǎn)心就好了。
根據(jù)子查詢(xún)返回值的數(shù)量,將子查詢(xún)可以分為標(biāo)量子查詢(xún)和多值子查詢(xún)。在使用比較符進(jìn)行子查詢(xún)時(shí),就要求必須是標(biāo)量子查詢(xún);如果是多值子查詢(xún)時(shí),使用比較符,就會(huì)拋出異常。
與標(biāo)量子查詢(xún)對(duì)應(yīng)的就是多值子查詢(xún)了,多值子查詢(xún)會(huì)返回一列、一行或者一個(gè)表,它們組成一個(gè)集合。我們一般使用的any、in、all和some等詞,將外部查詢(xún)與子查詢(xún)的結(jié)果進(jìn)行判斷。如果將any、in、all和some等詞與標(biāo)量子查詢(xún),就會(huì)得到空的結(jié)果。
獨(dú)立子查詢(xún)是不依賴(lài)外部查詢(xún)而運(yùn)行的子查詢(xún)。什么叫依賴(lài)外部查詢(xún)?先看下面兩個(gè)sql語(yǔ)句。
sql語(yǔ)句1:獲得所有hangzhou顧客的訂單號(hào)?!?br />
select order_id from table2 where customer_idin (select customer_id from table1 where city='hangzhou'); sql語(yǔ)句2:獲得城市為hangzhou,并且存在訂單的用戶(hù)。 select * from table1 where city='hangzhou' and exists (select * from table2 where table1.customer_id=table2.customer_id);
上面的兩條sql語(yǔ)句,雖然例子舉的有點(diǎn)不是很恰當(dāng),但是足以說(shuō)明這里的問(wèn)題了。
對(duì)于sql語(yǔ)句1,我們將子查詢(xún)單獨(dú)復(fù)制出來(lái),也是可以單獨(dú)執(zhí)行的,就是子查詢(xún)與外部查詢(xún)沒(méi)有任何關(guān)系。
對(duì)于sql語(yǔ)句2,我們將子查詢(xún)單獨(dú)復(fù)制出來(lái),就無(wú)法單獨(dú)執(zhí)行了,由于sql語(yǔ)句2的子查詢(xún)依賴(lài)外部查詢(xún)的某些字段,這就導(dǎo)致子查詢(xún)就依賴(lài)外部查詢(xún),就產(chǎn)生了相關(guān)性。
對(duì)于子查詢(xún),很多時(shí)候都會(huì)考慮到效率的問(wèn)題。當(dāng)我們執(zhí)行一個(gè)select語(yǔ)句時(shí),可以加上explain關(guān)鍵字,用來(lái)查看查詢(xún)類(lèi)型,查詢(xún)時(shí)使用的索引以及其它等等信息。比如這么用:
explainselect order_id from table2 where customer_idin (select customer_id from table1 where city='hangzhou');
使用獨(dú)立子查詢(xún),如果子查詢(xún)部分對(duì)集合的最大遍歷次數(shù)為n,外部查詢(xún)的最大遍歷次數(shù)為m時(shí),我們可以記為:O(m+n)。而如果使用相關(guān)子查詢(xún),它的遍歷 次數(shù)可能會(huì)達(dá)到O(m+m*n)??梢钥吹剑示蜁?huì)成倍的下降;所以,大伙在使用子查詢(xún)時(shí),一定要考慮到子查詢(xún)的相關(guān)性。
相關(guān)子查詢(xún)是指引用了外部查詢(xún)列的子查詢(xún),即子查詢(xún)會(huì)對(duì)外部查詢(xún)的每行進(jìn)行一次計(jì)算。但是在MySQL的內(nèi)部,會(huì)進(jìn)行動(dòng)態(tài)優(yōu)化,會(huì)隨著情況的不同會(huì) 有所不同。使用相關(guān)子查詢(xún)是最容易出現(xiàn)性能的地方。而關(guān)于sql語(yǔ)句的優(yōu)化,這又是一個(gè)非常大的話(huà)題了,只能通過(guò)實(shí)際的經(jīng)驗(yàn)積累,才能更好的去理解如何進(jìn) 行優(yōu)化。
EXISTS是一個(gè)非常牛叉的謂詞,它允許數(shù)據(jù)庫(kù)高效地檢查指定查詢(xún)是否產(chǎn)生某些行。根據(jù)子查詢(xún)是否返回行,該謂詞返回TRUE或FALSE。與其 它謂詞和邏輯表達(dá)式不同的是,無(wú)論輸入子查詢(xún)是否返回行,EXISTS都不會(huì)返回UNKNOWN,對(duì)于EXISTS來(lái)說(shuō),UNKNOWN就是FALSE。 還是上面的語(yǔ)句,獲得城市為hangzhou,并且存在訂單的用戶(hù)。
select * from table1 where city='hangzhou' and exists (select * from table2 where table1.customer_id=table2.customer_id);
關(guān)于IN和EXISTS的主要區(qū)別在于三值邏輯的判斷上。EXISTS總是返回TRUE或FALSE,而對(duì)于IN,除了TRUE、FALSE值外, 還有可能對(duì)NULL值返回UNKNOWN。但是在過(guò)濾器中,UNKNOWN的處理方式與FALSE相同,因此使用IN與使用EXISTS一樣,SQL優(yōu)化 器會(huì)選擇相同的執(zhí)行計(jì)劃。
說(shuō)到了IN和EXISTS幾乎是一樣的,但是,就不得不說(shuō)到NOT IN和NOT EXISTS,對(duì)于輸入列表中包含NULL值時(shí),NOT EXISTS和NOT IN之間的差異就表現(xiàn)的非常大了。輸入列表包含NULL值時(shí),IN總是返回TRUE和UNKNOWN,因此NOT IN就會(huì)得到NOT TRUE和NOT UNKNOWN,即FALSE和UNKNOWN。
上面也說(shuō)到了,在子查詢(xún)返回的值中,也可能返回一個(gè)表,如果將子查詢(xún)返回的虛擬表再次作為FROM子句的輸入時(shí),這就子查詢(xún)的虛擬表就成為了一個(gè)派生表。語(yǔ)法結(jié)構(gòu)如下:
FROM (subquery expression) AS derived_table_alias
由于派生表是完全的虛擬表,并沒(méi)有也不可能被物理地具體化。
很多查詢(xún)中需要使用子查詢(xún)。使用子查詢(xún)可以一次性的完成很多邏輯上需要多個(gè)步驟才能完成的SQL操作,同時(shí)也可以避免事務(wù)或者表鎖死。子查詢(xún)可以使查詢(xún)語(yǔ) 句很靈活,但子查詢(xún)的執(zhí)行效率不高。
子查詢(xún)時(shí),MySQL需要為內(nèi)層查詢(xún)語(yǔ)句的查詢(xún)結(jié)果建立一個(gè)臨時(shí)表。然后外層查詢(xún)語(yǔ)句再臨時(shí)表中查詢(xún)記錄。查詢(xún)完畢 后,MySQL需要撤銷(xiāo)這些臨時(shí)表。因此,子查詢(xún)的速度會(huì)受到一定的影響。如果查詢(xún)的數(shù)據(jù)量比較大,這種影響就會(huì)隨之增大。
在MySQL中可以使用連接查 詢(xún)來(lái)替代子查詢(xún)。連接查詢(xún)不需要建立臨時(shí)表,其速度比子查詢(xún)要快。
使用連接(JOIN)來(lái)代替子查詢(xún)
如:
例子1:
SELECT * FROM t1 WHERE t1.a1 NOTin (SELECT a2 FROM t2 ) 優(yōu)化后: SELECT * FROM t1 LEFT JOIN t2 ON t1.a1=t2.a2 WHERE t2.a2 IS NULL
例子2:
SELECT * FROM article WHERE (title,content,uid) IN (SELECT title,content,uid FROM blog) 優(yōu)化后: SELECT * FROM article innerjoin blog on (article.title=blog.title AND article.content=blog.content AND article.uid=blog.uid)
不能優(yōu)化的子查詢(xún):
1、mysql不支持子查詢(xún)合并和聚合函數(shù)子查詢(xún)優(yōu)化,mariadb對(duì)聚合函數(shù)子查詢(xún)進(jìn)行物化優(yōu)化;
2、mysql不支持from子句子查詢(xún)優(yōu)化,mariadb對(duì)from子句子查詢(xún)進(jìn)行子查詢(xún)上拉優(yōu)化;
3、mysql和mariadb對(duì)子查詢(xún)展開(kāi)提供有限的支持,如對(duì)主鍵的操作才能進(jìn)行上拉子查詢(xún)優(yōu)化;
4、mysql不支持exists子查詢(xún)優(yōu)化,mariadb對(duì)exists關(guān)聯(lián)子查詢(xún)進(jìn)行半連接優(yōu)化,對(duì)exists非關(guān)聯(lián)子查詢(xún)沒(méi)有進(jìn)一步進(jìn)行優(yōu)化;
5、mysql和mariadb不支持not exists子查詢(xún)優(yōu)化;
6、mysql和mariadb對(duì)in子查詢(xún),對(duì)滿(mǎn)足半連接語(yǔ)義的查詢(xún)進(jìn)行半連接優(yōu)化,再基于代價(jià)評(píng)估進(jìn)行優(yōu)化,兩者對(duì)半連接的代價(jià)評(píng)估選擇方式有差異;
7、mysql不支持not in子查詢(xún)優(yōu)化,mariadb對(duì)非關(guān)聯(lián)not in子查詢(xún)使用物化優(yōu)化,對(duì)關(guān)聯(lián)not in子查詢(xún)不做優(yōu)化;
8、mysql和mariadb對(duì)>all非關(guān)聯(lián)子查詢(xún)使用max函數(shù),all非關(guān)聯(lián)子查詢(xún)使用min函數(shù),對(duì)=all和非關(guān)聯(lián)子查詢(xún)使用exists優(yōu)化;
9、對(duì)>some和>any非關(guān)聯(lián)子查詢(xún)使用min函數(shù),對(duì)some和any非關(guān)聯(lián)子查詢(xún)使用max函數(shù),=any 和=some子查詢(xún)使用半連接進(jìn)行優(yōu)化,對(duì)>some和>any關(guān)聯(lián)子查詢(xún)以及some和any關(guān)聯(lián)子查詢(xún)只有exists 優(yōu)化。
到此這篇關(guān)于MySQL里面的子查詢(xún)的基本使用的文章就介紹到這了,更多相關(guān)MySQL 子查詢(xún)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
標(biāo)簽:揚(yáng)州 定西 無(wú)錫 溫州 福州 阿里 三明 山西
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《MySQL里面的子查詢(xún)的基本使用》,本文關(guān)鍵詞 MySQL,里,面的,子,查詢(xún),的,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。