主頁 > 資料庫 > 【MySQL學習】分組資料,使用子查詢

【MySQL學習】分組資料,使用子查詢

2021-03-07 17:01:30 資料庫

【MySQL學習】分組資料,使用子查詢

  • 分組資料
    • 資料分組
    • 創建分組
    • 過濾分組
    • 分組和排序
    • SELECT字句順序
  • 使用子查詢
    • 使用子查詢進行過濾
    • 作為計算欄位使用

分組資料

介紹兩個新的SELECT 陳述句字句,分別是GROUP BY 和 HAVING,

資料分組

之前我們介紹過使用聚集函式匯總資料,比如對1003供應商進行匯總

SELECT COUNT(*) AS num_prods
FROM products
WHERE vend_id =1003;

說明這個供應商提供7個產品

+-----------+
| num_prods |
+-----------+
|         7 |
+-----------+

當我們需要回傳每個供應商提供的產品數目,或者回傳只提供單項產品的供應商所提供的產品,或者回傳提供十個以上產品的供應商,我們就需要進行資料分組,以便能對每個組進行聚集計算,

創建分組

分組使用 SELECT 陳述句中的 GROUP BY 字句建立的
舉個例子

SELECT vend_id, COUNT(*) AS num_prods
FROM products
GROUP BY vend_id;

這個陳述句制定了資料庫按照供應商id排序并進行資料分組,導致每次計算產品數量不是對著所有產品,而是對某個供應商的所有產品計數

+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
|    1001 |         3 |
|    1002 |         2 |
|    1003 |         7 |
|    1005 |         2 |
+---------+-----------+

這個陳述句有這些注意事項

  • GROUP BY 子句可以包含任意數目的列,這使得能對分組進行嵌套,為資料分組提供更細致的控制,
  • 如果在 GROUP BY 子句中嵌套了分組,資料將在最后規定的分組上進行匯總,換句話說,在建立分組時,指定的所有列都一起計算(所以不能從個別的列取回資料),
  • GROUP BY 子句中列出的每個列都必須是檢索列或有效的運算式(但不能是聚集函式),如果在 SELECT 中使用運算式,則必須在GROUP BY 子句中指定相同的運算式,不能使用別名,
  • 除聚集計算陳述句外, SELECT 陳述句中的每個列都必須在 GROUP BY 子句中給出,
  • 如果分組列中具有 NULL 值,則 NULL 將作為一個分組回傳,如果列中有多行 NULL 值,它們將分為一組,
  • GROUP BY 子句必須出現在 WHERE 子句之后, ORDER BY 子句之前,
  • 使用 WITH ROLLUP 關鍵字,可以得到每個分組以及每個分組匯總級別(針對每個分組)的值

過濾分組

我們已經看到了 WHERE 子句的作用,但是,在這個例子中 WHERE 不能完成任務,因為 WHERE 過濾指定的是行而不是分組,事實上, WHERE 沒有分組的概念,想要過濾分組,則使用 HAVING 子句, HAVING 非常類似于 WHERE ,事實上,目前為止所學過的所有型別的 WHERE 子句都可以用 HAVING 來替代,唯一的差別是
WHERE 過濾行,而 HAVING 過濾分組,

SELECT cust_id, COUNT(*) AS orders
FROM orders
GROUP BY cust_id
HAVING COUNT(*) >= 2;

這樣輸出的就是含有兩個以上訂單的組,


+---------+--------+
| cust_id | orders |
+---------+--------+
|   10001 |      2 |
+---------+--------+

HAVING 和 WHERE 的差別 這里有另一種理解方法, WHERE 在資料分組前進行過濾, HAVING 在資料分組后進行過濾,這是一個重要的區別, WHERE 排除的行不包括在分組中,這可能會改變計算值,從而影響 HAVING 子句中基于這些值過濾掉的分組,

為了理解這兩種子句的不同,我們再看一個例子,如何列出具有兩個以上、價格為10的產品供應商

SELECT vend_id, COUNT(*) AS num_prods
FROM products
WHERE prod_price >= 10
GROUP BY vend_id
HAVING COUNT(*) >= 2; 

這里的 WHERE 只呼叫價格大于等于10的商品,而 HAVING 則篩選了有兩個以上(價格大于等于10)的商品的供應商,

+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
|    1003 |         4 |
|    1005 |         2 |
+---------+-----------+

同時我們應該注意到,WHERE 的觸發是在前面的,我們去掉 WHERE 子句來看看結果:

SELECT vend_id, COUNT(*) AS num_prods
FROM products
GROUP BY vend_id
HAVING COUNT(*) >= 2; 

輸出是:

+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
|    1001 |         3 |
|    1002 |         2 |
|    1003 |         7 |
|    1005 |         2 |
+---------+-----------+

分組和排序

分組和排序分別采用 GROUP BY 和 ORDER BY,兩者常常聯合起來完成作業,因為ORDER BY 是唯一能保證資料正確排序的方法,

我們舉一個簡單的例子,下面的例子檢索總計訂單價格大于等于50的訂單的訂單號和總計訂單價格:

SELECT order_num, SUM(quantity*item_price) AS ordertotal
FROM orderitems
GROUP BY order_num
HAVING SUM(quantity*item_price) >= 50;
+-----------+------------+
| order_num | ordertotal |
+-----------+------------+
|     20005 |     149.87 |
|     20006 |      55.00 |
|     20007 |    1000.00 |
|     20008 |     125.00 |
+-----------+------------+

在這個例子中, GROUP BY 子句用來按訂單號( order_num 列)分組資料,以便 SUM(*) 函式能夠回傳總計訂單價格, HAVING 子句過濾資料,使得只回傳總計訂單價格大于等于 50 的訂單,最后,用 ORDER BY 子句排序輸出,

SELECT字句順序

這里回顧一下 SELECT 陳述句中的子句的順序

子句說明是否必須使用
SELECT要回傳的列或者運算式
FROM從中檢索資料的表僅在從表中選擇資料時使用
WHERE行級過濾
GROUP BY分組說明僅在按組計算聚集時使用
HAVING組級過濾
ORDER BY輸出排序順序
LIMIT檢索行數

使用子查詢

MySQL 4.1引入了對子查詢的支持,所以要想使用下面描述的SQL,必須使用MySQL 4.1或更高級的版本,SELECT陳述句 是SQL的查詢,迄今為止我寫的所有 SELECT 陳述句都是簡單查詢,即從單個資料庫表中檢索資料的單條陳述句,

SQL還允許創建子查詢(subquery),即嵌套在其他查詢中的查詢,為什么要這樣做呢?理解這個概念的最好方法是考察幾個例子,

使用子查詢進行過濾

測驗資料中中使用的資料庫表都是關系表(關于每個表及關系的描述,請參閱《MySQL必知必會》附錄B),訂單存盤在兩個表中,對于包含訂單號、客戶ID、訂單日期的每個訂單, orders 表存盤一行,各訂單的物品存盤在相關的orderitems 表中, orders 表不存盤客戶資訊,它只存盤客戶的ID,實際的客戶資訊存盤在 customers 表中,

現在,假如需要列出訂購物品 TNT2 的所有客戶,應該怎樣檢索?下面列出具體的步驟,

  1. 檢索包含物品 TNT2 的所有訂單的編號,
  2. 檢索具有前一步驟列出的訂單編號的所有客戶的ID,
  3. 檢索前一步驟回傳的所有客戶ID的客戶資訊,

上述每個步驟都可以單獨作為一個查詢來執行,可以把一條 SELECT陳述句回傳的結果用于另一條 SELECT 陳述句的 WHERE 子句,

也可以使用子查詢來把3個查詢組合成一條陳述句,

SELECT cust_id
FROM orders
WHERE order_num IN (SELECT order_num
					FROM orderitems
					WHERE prod_id ='TNT2');

值得注意的是,子查詢總是自內向外處理,

+---------+
| cust_id |
+---------+
|   10001 |
|   10004 |
+---------+

現在我們得到了所有訂購物品 TNT2 的客戶的 ID (10001,10004),下一步是檢索這些客戶的資訊:

SELECT cust_name,cust_contact
FROM customers
WHERE cust_id IN (SELECT cust_id
					FROM orders
					WHERE order_num IN (SELECT order_num
										FROM orderitems
										WHERE prod_id ='TNT2'));
+----------------+--------------+
| cust_name      | cust_contact |
+----------------+--------------+
| Coyote Inc.    | Y Lee        |
| Yosemite Place | Y Sam        |
+----------------+--------------+

我們成功得到了結果, 可見,在 WHERE 子句中使用子查詢能夠撰寫出功能很強并且很靈活的SQL陳述句,對于能嵌套的子查詢的數目沒有限制,不過在實際使用時由于性能的限制,不能嵌套太多的子查詢,

雖然子查詢一般與 IN 運算子結合使用,但也可以用于測驗等于( = )、不等于( <> )等,

作為計算欄位使用

使用子查詢的另一方法是創建計算欄位,假如需要顯示 customers表中每個客戶的訂單總數,訂單與相應的客戶ID存盤在 orders 表中,

為了執行這個操作,遵循下面的步驟,

  1. 從 customers 表中檢索客戶串列,
  2. 對于檢索出的每個客戶,統計其在 orders 表中的訂單數目,

正如前兩章所述,可使用 SELECT COUNT ( *) 對表中的行進行計數,并且通過提供一條 WHERE 子句來過濾某個特定的客戶ID,可僅對該客戶的訂單進行計數,

例如,下面的代碼對客戶 10001 的訂單進行計數:

SELECT COUNT(*) AS orders
FROM orders
WHERE cust_id = 10001

為了對每個客戶執行 COUNT() 計算,應該將 COUNT() 作為一個子查詢,

請看下面的代碼:

SELECT cust_name,
			cust_state,
			(SELECT COUNT(*) AS orders
			FROM orders
			WHERE orders.cust_id = customers.cust_id) AS orders
FROM customers
ORDER BY cust_name;

+----------------+------------+--------+
| cust_name      | cust_state | orders |
+----------------+------------+--------+
| Coyote Inc.    | MI         |      2 |
| E Fudd         | IL         |      1 |
| Mouse House    | OH         |      0 |
| Wascals        | IN         |      1 |
| Yosemite Place | AZ         |      1 |
+----------------+------------+--------+

這 條 SELECT 語 句 對 customers 表 中 每 個 客 戶 返 回 3 列 :cust_name 、 cust_state 和 orders , orders 是一個計算欄位,它是由圓括號中的子查詢建立的,該子查詢對檢索出的每個客戶執行一次,在此例子中,該子查詢執行了5次,因為檢索出了5個客戶,

子查詢中的 WHERE 子句與前面使用的 WHERE 子句稍有不同,因為它使用了完全限定列名(在第4章中首次提到),下面的陳述句告訴SQL比較orders 表中的 cust_id 與當前正從 customers 表中檢索的 cust_id :


WHERE orders.cust_id = customers.cust_id

這種型別的子查詢稱為相關子查詢 (correlated subquery) ,任何時候只要列名可能有多義性,就必須使用這種語法(表名和列名由一個句點分隔),

SELECT cust_name,
			cust_state,
			(SELECT COUNT(*) AS orders
			FROM orders
			WHERE cust_id = cust_id) AS orders
FROM customers
ORDER BY cust_name;

表中有兩個相同的 cust_id 列,一個在 customers 中,另一個在orders 中,需要比較這兩個列以正確地把訂單與它們相應的顧客匹配,如果不完全限定列名,MySQL將假定你是對 orders 表中的 cust_id 進行自身比較,而 SELECT COUNT(*) FROM orders WHERE cust_id = cust_id;總是回傳 orders 表中的訂單總數(因為MySQL查看每個訂單的 cust_id是否與本身匹配,當然,它們總是匹配的),

所以輸出是:

`+----------------+------------+--------+
| cust_name      | cust_state | orders |
+----------------+------------+--------+
| Coyote Inc.    | MI         |      5 |
| E Fudd         | IL         |      5 |
| Mouse House    | OH         |      5 |
| Wascals        | IN         |      5 |
| Yosemite Place | AZ         |      5 |
+----------------+------------+--------+

值得注意的是,雖然這里給出的樣例代碼運行良好,但它并不是解決這種資料檢索的最有效的方法,在后面的章節中我們還要遇到這個例子

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/267173.html

標籤:其他

上一篇:MySQL8 常用命令之DQL(多表聯查)

下一篇:C語言中的指標與陣列

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more