mysql與子查詢

原文鏈接

同樣的,使用goods表來練習子查詢,表結構如下:

在這裏插入圖片描述

所有數據(cat_id與category.cat_id關聯):

在這裏插入圖片描述

類別表:

在這裏插入圖片描述

mingoods(連接查詢時作測試)

在這裏插入圖片描述

回到頂部
一、子查詢
1、where型子查詢:把內層查詢的結果作爲外層查詢的比較條件
1.1 查詢id最大的一件商品(使用排序+分頁實現)

:mysql> SELECT goods_id,goods_name,shop_price FROM goods ORDER BY goods_id DESC LIMIT 1;

在這裏插入圖片描述

1.2 查詢id最大的一件商品(使用where子查詢實現)

: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、from型子查詢:把內層的查詢結果當成臨時表,供外層sql再次查詢。查詢結果集可以當成表看待。臨時表要使用一個別名。
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.exists型子查詢:把外層sql的結果,拿到內層sql去測試,如果內層的sql成立,則該行取出。內層查詢是exists後的查詢。
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後的內層查詢能查出數據,則表示存在;爲空則不存在。

在這裏插入圖片描述

  1. any, in 子查詢
      
      在這裏插入圖片描述

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

在這裏插入圖片描述

小類別表(左右連接時做對比)

在這裏插入圖片描述

1.全相乘(不是全連接、連接查詢),全相乘是作笛卡爾積  
  兩表全相乘,就是直接從兩張表裏查詢;從查詢的截圖看出,總共查出了 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;

在這裏插入圖片描述

2.左連接查詢 left join … on …
  語法:select A.filed, [A.filed2, … ,] B.filed, [B.filed4…,] from as A left join as B on

假設有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;

在這裏插入圖片描述

3.右連接查詢 right join … on …
  語法:select A.field1,A.field2,…, B.field3,B.field4 from A right join B on

右連接查詢跟左連接查詢類似,只是右連接是以右表爲主表,會將右表所有數據查詢出來,而左表則根據條件去匹配,如果左表沒有滿足條件的行,則左邊默認顯示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;

在這裏插入圖片描述

  1. 內連接 inner join … on …
      語法:select A.field1,A.field2,…, B.field3, B.field4 from A inner join B on

內連接查詢,就是取左連接和右連接的交集,如果兩邊不能匹配條件,則都不取出。

:mysql> SELECT g.goods_name,g.cat_id, c.* from mingoods g INNER JOIN mincategory c ON g.cat_id = c.cat_id;

在這裏插入圖片描述

  1. 全連接 full join … on …
      語法:select … from full join on

全連接會將兩個表的所有數據查詢出來,不滿足條件的爲NULL。

全連接查詢跟全相乘查詢的區別在於,如果某個項不匹配,全相乘不會查出來,全連接會查出來,而連接的另一邊則爲NULL。

在這裏插入圖片描述
6. 聯合查詢 union
  語法:select A.field1 as f1, A.field2 as f2 from A union (select B.field3 as f1, field4 as f2 from 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 的縮寫。

_

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章