1、子查詢html
注:該MySql系列博客僅爲我的學習筆記。mysql
一樣的,使用goods表來練習子查詢,表結構以下:sql
全部數據(cat_id與category.cat_id關聯):數據庫
類別表:express
mingoods(鏈接查詢時做測試)學習
回到頂部測試
1.1 查詢id最大的一件商品(使用排序+分頁實現)優化
:mysql> SELECT goods_id,goods_name,shop_price FROM goods ORDER BY goods_id DESC LIMIT 1;3d
1.2 查詢id最大的一件商品(使用where子查詢實現)htm
:mysql> SELECT goods_id,goods_name,shop_price FROM goods WHERE goods_id = (SELECT MAX(goods_id) FROM goods);
1.3 查詢每一個類別下id最大的商品(使用where子查詢實現)
:mysql> SELECT goods_id,goods_name,cat_id,shop_price FROM goods WHERE goods_id IN (SELECT MAX(goods_id) FROM goods GROUP BY cat_id);
2.1 查詢每一個類別下id最大的商品(使用from型子查詢)
:mysql > SELECT goods_id,goods_name,cat_id,shop_price FROM
-> (SELECT goods_id,goods_name,cat_id,shop_price FROM goods ORDER BY cat_id ASC,goods_id DESC) AS tmp
-> GROUP BY cat_id;
子查詢查出的結果集看第二張圖,能夠看到每一個類別的第一條的商品id都爲該類別下的最大值。而後將這個結果集做爲一張臨時表,巧妙的使用group by 查詢出每一個類別下的第一條記錄,即爲每一個類別下商品id最大。
3.1 從類別表中取出其類別下有商品的類別(若是該類別下沒有商品,則不取出),[使用where子查詢]
:mysql> SELECT c.cat_id,c.cat_name FROM category c WHERE c.cat_id IN (SELECT g.cat_id FROM goods g GROUP BY g.cat_id);
3.2 從類別表中取出其類別下有商品的類別(若是該類別下沒有商品,則不取出),[使用exists子查詢]
:mysql> SELECT c.cat_id,c.cat_name FROM category c WHERE EXISTS (SELECT 1 FROM goods g WHERE g.cat_id = c.cat_id);
exists子查詢,若是exists後的內層查詢能查出數據,則表示存在;爲空則不存在。
4.1 使用 any 查出類別大於任何一個num值的類別。
ANY關鍵詞必須後面接一個比較操做符。ANY關鍵詞的意思是「對於在子查詢返回的列中的任一數值,若是比較結果爲TRUE的話,則返回TRUE」。
:mysql> SELECT cat_id,cat_name FROM category WHERE cat_id > ANY (SELECT num FROM nums);
4.2 使用 in 查出cat_id 等於num的類別
:mysql> SELECT cat_id,cat_name FROM category WHERE cat_id IN (SELECT num FROM nums);
4.3 in 的效果 跟 =any 的效果是同樣的。
4.4 使用 all 查詢
詞語ALL必須接在一個比較操做符的後面。ALL的意思是「對於子查詢返回的列中的全部值,若是比較結果爲TRUE,則返回TRUE。」
4.5 not in 和 <> any 的效果是同樣的
NOT IN不是<> ANY的別名,可是是<> ALL的別名
1. where型子查詢:把內層查詢的結果做爲外層查詢的比較條件。
from型子查詢:把內層的查詢結果當成臨時表,供外層sql再次查詢。查詢結果集能夠當成表看待,臨時表須要一個別名。
exists型子查詢:把外層sql的結果,拿到內層sql去測試,若是內層的sql成立,則該行取出。內層sql是exists後的查詢。
2. 子查詢也能夠嵌套在其它子查詢中,嵌套程度能夠很深。子查詢必需要位於圓括號中。
3. 子查詢的主要優點爲:
子查詢容許結構化的查詢,這樣就能夠把一個語句的每一個部分隔離開。
有些操做須要複雜的聯合和關聯。子查詢提供了其它的方法來執行這些操做。
4. ANY關鍵詞必須後面接一個比較操做符。ANY關鍵詞的意思是「對於在子查詢返回的列中的任一數值,若是比較結果爲TRUE的話,則返回TRUE」。
詞語 IN 是 =ANY 的別名,兩者效果相同。
NOT IN不是 <> ANY 的別名,可是是 <> ALL 的別名。
5. 詞語ALL必須接在一個比較操做符的後面。ALL的意思是「對於子查詢返回的列中的全部值,若是比較結果爲TRUE,則返回TRUE。」
6. 優化子查詢
①. 有些子句會影響在子查詢中的行的數量和順序,經過加一些限制條件來限制子查詢查出來的條數。例如:
SELECT * FROM t1 WHERE t1.column1 IN (SELECT column1 FROM t2 ORDER BY column1);
SELECT * FROM t1 WHERE t1.column1 IN (SELECT DISTINCT column1 FROM t2);
SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 LIMIT 1);
②. 用子查詢替換聯合。例如:
SELECT DISTINCT column1 FROM t1 WHERE t1.column1 IN (SELECT column1 FROM t2);
代替這個:SELECT DISTINCT t1.column1 FROM t1, t2 WHERE t1.column1 = t2.column1;
學習鏈接查詢,先了解下"笛卡爾積",看下百度給出的解釋:
在數據庫中,一張表就是一個集合,每一行就是集合中的一個元素。表之間做聯合查詢便是做笛卡爾乘積,好比A表有5條數據,B表有8條數據,若是不做條件篩選,那麼兩表查詢就有 5 X 8 = 40 條數據。
先看下用到的測試表基本信息:咱們要實現的功能就是查詢商品的時候,從類別表將商品類別名稱關聯查詢出來。
行數:類別表14條,商品表4條
結構:商品表和類別表都有一個cat_id
小類別表(左右鏈接時作對比)
兩表全相乘,就是直接從兩張表裏查詢;從查詢的截圖看出,總共查出了 4 X 14 = 56 條記錄,這些記錄是笛卡爾乘積的結果,即兩兩組合;
但咱們要的是每一個商品信息顯示類別名稱而已,這裏卻查出了56條記錄,其中有52條記錄都是無效的數據,全相乘的查詢效率低。
:mysql> SELECT goods_id,goods_name,cat_name FROM mingoods,category;
若是在兩張表裏有相同字段,作聯合查詢的時候,要區別表名,不然會報錯誤(模糊不清)
:mysql> SELECT goods_name,cat_id,cat_name FROM mingoods,category;
添加條件,使兩表關聯查詢,這樣查出來就是商品和類別一一對應了。雖然這裏查出來4條記錄,可是全相乘效率低,全相乘會在內存中生成一個很是大的數據(臨時表),由於有不少沒必要要的數據。
若是一張表有10000條數據,另外一張表有10000條數據,兩表全相乘就是100W條數據,是很是消耗內存的。並且,全相乘不能好好的利用索引,由於全相乘生成一張臨時表,臨時表裏是沒有索引的,大大下降了查詢效率。
:mysql> SELECT g.goods_name,g.cat_id AS g_cat_id, c.cat_id AS c_cat_id, c.cat_name FROM mingoods g, category c WHERE g.cat_id = c.cat_id;
語法:select A.filed, [A.filed2, .... ,] B.filed, [B.filed4...,] from <left table> as A left join <right table> as B on <expression>
假設有A、B兩張表,左鏈接查詢即 A表在左不動,B表在右滑動,A表與B表經過一個關係來關聯行,B表去匹配A表。
2.1先來看看on後的條件恆爲真的狀況
:mysql> SELECT g.goods_name,g.cat_id, c.cat_id ,c.cat_name FROM mingoods g LEFT JOIN category c ON 1;
跟全相乘相比,從截圖能夠看出,總記錄數仍然不變,仍是 4 X 14 = 56 條記錄。但此次是商品表不動,類別表去匹配,由於每次都爲真,因此將全部的記錄都查出來了。左鏈接,其實就能夠當作左表是主表,右表是從表。
2.2 根據cat_id使兩表關聯行
:mysql> SELECT g.goods_name,g.cat_id,c.cat_id,c.cat_name FROM mingoods g LEFT JOIN category c ON g.cat_id = c.cat_id;
使用左鏈接查詢達到了一樣的效果,可是不會有其它冗餘數據,查詢速度快,消耗內存小,並且使用了索引。左鏈接查詢效率相比於全相乘的查詢效率快了10+倍以上。
左鏈接時,mingoods表(左表)不動,category表(右表)根據條件去一條條匹配,雖然說category表也是讀取一行行記錄,而後判斷cat_id是否跟mingoods表的相同,可是,左鏈接使用了索引,cat_id創建了索引的話,查詢速度很是快,因此總體效率相比於全相乘要快得多,全相乘沒有使用索引。
2.3 查詢出第四個類別下的商品,要求顯示商品名稱
:mysql> SELECT g.goods_name,g.cat_id,c.cat_name,g.shop_price FROM goods g LEFT JOIN category c ON g.cat_id = c.cat_id WHERE g.cat_id = 4;
2.4 對於左鏈接查詢,若是右表中沒有知足條件的行,則默認填充NULL。
:mysql> SELECT g.goods_name,g.cat_id AS g_cat_id, c.cat_id AS c_cat_id,c.cat_id FROM mingoods g LEFT JOIN mincategory c ON g.cat_id = c.cat_id;
語法:select A.field1,A.field2,..., B.field3,B.field4 from <left table> A right join <right table> B on <expression>
右鏈接查詢跟左鏈接查詢相似,只是右鏈接是以右表爲主表,會將右表全部數據查詢出來,而左表則根據條件去匹配,若是左表沒有知足條件的行,則左邊默認顯示NULL。左右鏈接是能夠互換的。
:mysql> SELECT g.goods_name,g.cat_id AS g_cat_id, c.cat_id AS c_cat_id,c.cat_name FROM mingoods g RIGHT JOIN mincategory c ON g.cat_id = c.cat_id;
語法:select A.field1,A.field2,.., B.field3, B.field4 from <left table> A inner join <right table> B on <expression>
內鏈接查詢,就是取左鏈接和右鏈接的交集,若是兩邊不能匹配條件,則都不取出。
:mysql> SELECT g.goods_name,g.cat_id, c.* from mingoods g INNER JOIN mincategory c ON g.cat_id = c.cat_id;
語法:select ... from <left table> full join <right table> on <expression>
全鏈接會將兩個表的全部數據查詢出來,不知足條件的爲NULL。
全鏈接查詢跟全相乘查詢的區別在於,若是某個項不匹配,全相乘不會查出來,全鏈接會查出來,而鏈接的另外一邊則爲NULL。
語法:select A.field1 as f1, A.field2 as f2 from <table1> A union (select B.field3 as f1, field4 as f2 from <table2> B)
union是求兩個查詢的並集。union合併的是結果集,不區分來自於哪一張表,因此能夠合併多張表查詢出來的數據。
6.1 將兩張表的數據合併查詢出來
:mysql> SELECT id, content, user FROM comment UNION (SELECT id, msg AS content, user FROM feedback);
6.2 union查詢,列名不一致時,以第一條sql語句的列名對齊
:mysql> SELECT id, content, user FROM comment UNION (SELECT id, msg, user FROM feedback);
6.3 使用union查詢會將重複的行過濾掉
:mysql> SELECT content,user FROM comment UNION (SELECT msg, user FROM feedback);
6.4 使用union all查詢全部,重複的行不會被過濾
:mysql> SELECT content,user FROM comment UNION ALL (SELECT msg, user FROM feedback);
6.5 union查詢,若是列數不相等,會報列數不相等錯誤
6.6 union 後的結果集還能夠再作篩選
:mysql> SELECT id,content,user FROM comment UNION ALL (SELECT id, msg, user FROM feedback) ORDER BY id DESC;
union查詢時,order by放在內層sql中是不起做用的;由於union查出來的結果集再排序,內層的排序就沒有意義了;所以,內層的order by排序,在執行期間,被mysql的代碼分析器給優化掉了。
:mysql> (SELECT id,content,user FROM comment ORDER BY id DESC) UNION ALL (SELECT id, msg, user FROM feedback ORDER BY id DESC);
order by 若是和limit一塊兒使用,就顯得有意義了,就不會被優化掉
mysql> ( SELECT goods_name,cat_id,shop_price FROM goods WHERE cat_id = 3 ORDER BY shop_price DESC LIMIT 3 )
-> UNION
-> ( SELECT goods_name,cat_id,shop_price FROM goods WHERE cat_id = 4 ORDER BY shop_price DESC LIMIT 2 );
6.7 練習
:mysql> SELECT name, SUM(money) FROM ( ( SELECT * FROM A ) UNION ALL ( SELECT * FROM B ) ) tmp GROUP BY name;
1.在數據庫中,一張表就是一個集合,每一行就是集合中的一個元素。鏈接查詢便是做笛卡爾積,好比A表有1W條數據,B表有1W條數據,那麼兩表查詢就有 1W X 1W = 100W 條數據
2.若是在兩張表裏有相同字段,作聯合查詢的時候,要區別表名,不然會報錯誤(ambiguous 模糊不清)
3.全相乘效率低,全相乘會在內存中生成一個很是大的數據(臨時表),由於有不少沒必要要的數據。
若是一張表有10000條數據,另外一張表有10000條數據,兩表全相乘就是100W條數據,是很是消耗內存的。
並且,全相乘不能好好的利用索引,由於全相乘生成一張臨時表,臨時表裏是沒有索引的,大大下降了查詢效率。
4.左鏈接查詢時,以左表爲主表,會將左表全部數據查詢出來;左表不動,右表根據條件去一條條匹配,若是沒有知足條件的記錄,則右邊返回NULL。
右鏈接查詢值,以右表爲主表,會將右表全部數據查詢出來,右表不動,左表則根據條件去匹配,若是左表沒有知足條件的行,則左邊返回NULL。
左右鏈接是能夠互換的:A left join B == B right join A (都是以A爲主表) 。
左右鏈接既然能夠互換,出於移植兼容性方面的考慮,儘可能使用左鏈接。
5.鏈接查詢時,雖然說也是讀取一行行記錄,而後判斷是否知足條件,可是,鏈接查詢使用了索引,條件列創建了索引的話,查詢速度很是快,因此總體效率相比於全相乘要快得多,全相乘是沒有使用索引的。
使用鏈接查詢,查詢速度快,消耗內存小,並且使用了索引。鏈接查詢效率相比於全相乘的查詢效率快了10+倍以上。
6.內鏈接查詢,就是取左鏈接和右鏈接的交集,若是兩邊不能匹配條件,則都不取出。
7.MySql能夠用union(聯合查詢)來查出左鏈接和右鏈接的並集。
union查詢會過濾重複的行,union all 不會過濾重複的行。
union查詢時,union之間的sql列數必須相等,列名以第一條sql的列爲準;列類型能夠不同,但沒太大意義。
union查詢時,order by放在內層sql中是不起做用的;由於union查出來的結果集再排序,內層的排序就沒有意義了;所以,內層的order by排序,在執行期間,被mysql的代碼分析器給優化掉了。
可是,order by 若是和limit一塊兒使用,就顯得有意義了,會影響最終結果集,就不會被優化掉。order by會根據最終是否會影響結果集而選擇性的優化。
8. LEFT JOIN 是 LEFT OUTER JOIN 的縮寫,同理,RIGHT JOIN 是 RIGHT OUTER JOIN 的縮寫;JOIN 是 INNER JOIN 的縮寫。