天天看點

一文帶你剖析MySQL到底都有哪些常用的查詢去重(過濾重複資料)别名分頁查詢(限制查詢結果的條數)排序(對查詢結果排序)條件查詢模糊查詢範圍查詢空值查詢分組查詢(重要&常用)過濾分組

去重(過濾重複資料)

  • 在 MySQL 中使用 SELECT 語句執行簡單的資料查詢時,傳回的是所有比對的記錄。如果表中的某些字段沒有唯一性限制,那麼這些字段就可能存在重複值。為了實作查詢不重複的資料,MySQL 提供了 DISTINCT 關鍵字。
  • DISTINCT 關鍵字的主要作用就是對資料表中一個或多個字段重複的資料進行過濾,隻傳回其中的一條資料給使用者。
  • 使用 DISTINCT 關鍵字時需要注意以下幾點:
  1. DISTINCT 關鍵字隻能在 SELECT 語句中使用。
  2. 在對一個或多個字段去重時,DISTINCT 關鍵字必須在所有字段的最前面。
  3. 如果 DISTINCT 關鍵字後有多個字段,則會對多個字段進行組合去重,也就是說,隻有多個字段組合起來完全是一樣的情況下才會被去重。
# 對history表的value字段去重
select distinct history.value from zabbix.hosts,zabbix.items,zabbix.history where hosts.name="zbxproxy03" and items.name="Context switches per second" and items.itemid=history.itemid;

# 對history表的clock和value字段去重
select distinct history.clock,history.value from zabbix.hosts,zabbix.items,zabbix.history where hosts.name="zbxproxy03" and items.name="Context switches per second" and items.itemid=history.itemid;

# 查詢去重之後的記錄的條數
select count(distinct history.clock,history.value) from zabbix.hosts,zabbix.items,zabbix.history where hosts.name="zbxproxy03" and items.name="Context switches per second" and items.itemid=history.itemid;           

複制

别名

  • 為了查詢友善,MySQL 提供了 AS 關鍵字來為表和字段指定别名
  • 當表名很長或者執行一些特殊查詢的時候,為了友善操作,可以為表指定一個别名,用這個别名代替表原來的名稱。
  • 表的别名不能與該資料庫的其它表同名。字段的别名不能與該表的其它字段同名。在條件表達式中不能使用字段的别名
  • 表别名隻在執行查詢時使用,并不在傳回結果中顯示。而字段定義别名之後,會傳回給用戶端顯示,顯示的字段為字段的别名。
  1. 表别名
# 下面為 zabbix 庫中的 hosts 表指定别名 h
select h.name,h.host from zabbix.hosts as h where status=0;           

複制

  1. 字段别名
# 給h.name字段指定别名“主機名”,inter.ip字段指定别名“ip位址”
mysql> select h.name as "主機名",inter.ip as "ip位址" from zabbix.hosts as h,zabbix.interface as inter where h.name="zbxproxy03" and h.hostid=inter.hostid;
+------------+----------------+
| 主機名     | ip位址         |
+------------+----------------+
| zbxproxy03 | 192.168.11.157 |
+------------+----------------+
1 row in set (0.00 sec)           

複制

分頁查詢(限制查詢結果的條數)

  • 當資料表中有上萬條資料時,一次性查詢出表中的全部資料會降低資料傳回的速度,同時給資料庫伺服器造成很大的壓力。這時就可以用 LIMIT 關鍵字來限制查詢結果傳回的條數。
  • LIMIT 是 MySQL 中的一個特殊關鍵字,用于指定查詢結果從哪條記錄開始顯示,一共顯示多少條記錄。
  • LIMIT 關鍵字有 3 種使用方式,即指定初始位置、不指定初始位置以及與 OFFSET 組合使用。

1. 指定初始位置

  • LIMIT 關鍵字可以指定查詢結果從哪條記錄開始顯示,顯示多少條記錄。
  • LIMIT 指定初始位置的基本文法格式如下:
LIMIT 初始位置,記錄數           

複制

  • 其中,“初始位置”表示從哪條記錄開始顯示;“記錄數”表示顯示記錄的條數。第一條記錄的位置是 0,第二條記錄的位置是 1。後面的記錄依次類推。
  • 注意:LIMIT 後的兩個參數必須都是正整數。
  • 規律如下:
第1頁 limit 0,10 # 按分頁顯示,每頁顯示10條記錄,從0開始,目前是第1頁(第2頁的計算方式是,10+0=10,是以,要顯示第2頁,就要從10開始了)
第2頁 limit 10,10 # 按分頁顯示,每頁顯示10條記錄,從10開始,目前是第2頁(第3頁的計算方式是,10+10=20,是以,要顯示第3頁,就要從20開始了)
第3頁 limit 20,10 # 按分頁顯示,每頁顯示10條記錄,從20開始,目前是第3頁
第4頁 limit 30,10 # 按分頁顯示,每頁顯示10條記錄,從30開始,目前是第4頁
第5頁 limit 40,10 # 按分頁顯示,每頁顯示10條記錄,從40開始,目前是第5頁
...依此類推...           

複制

案例:從第3行記錄開始,每頁顯示5行記錄

select FROM_UNIXTIME(his.clock),his.value from history as his limit 3,5;           

複制

2. 不指定初始位置

  • LIMIT 關鍵字不指定初始位置時,記錄從第一條記錄開始顯示。顯示記錄的條數由 LIMIT 關鍵字指定。
  • LIMIT 不指定初始位置的基本文法格式如下:
LIMIT 記錄數           

複制

  • 其中,“記錄數”表示顯示記錄的條數。如果“記錄數”的值小于查詢結果的總數,則會從第一條記錄開始,顯示指定條數的記錄。如果“記錄數”的值大于查詢結果的總數,則會直接顯示查詢出來的所有記錄。

案例:顯示 hosts 表查詢結果的前 3 行,SQL 語句和運作結果如下。

mysql> select hostid,name from zabbix.hosts where status=0 limit 3;
+--------+------------+
| hostid | name       |
+--------+------------+
|  10084 | zbxser01   |
|  10331 | {#HV.NAME} |
|  10332 | {#VM.NAME} |
+--------+------------+
3 rows in set (0.00 sec)           

複制

  • 結果中隻顯示了 3 條記錄,說明“LIMIT 3”限制了顯示條數為 3。

3. LIMIT和OFFSET組合使用

  • LIMIT 可以和 OFFSET 組合使用,文法格式如下:
LIMIT 記錄數 OFFSET 初始位置           

複制

  • 參數和 LIMIT 文法中參數含義相同,“初始位置”指定從哪條記錄開始顯示;“記錄數”表示顯示記錄的條數。

案例

mysql> select name from zabbix.hosts limit 5 offset 100;
+---------------------------------------------------------------+
| name                                                          |
+---------------------------------------------------------------+
| Template Module Windows physical disks by Zabbix agent active |
| Template Module Windows services by Zabbix agent              |
| Template Module Windows services by Zabbix agent active       |
| Template Module Zabbix agent                                  |
| Template Module Zabbix agent active                           |
+---------------------------------------------------------------+
5 rows in set (0.00 sec)           

複制

排序(對查詢結果排序)

  • 關鍵字:order by
  • 通過條件查詢語句可以查詢到符合使用者需求的資料,但是查詢到的資料一般都是按照資料最初被添加到表中的順序來顯示。為了使查詢結果的順序滿足使用者的要求,MySQL 提供了 ORDER BY 關鍵字來對查詢結果進行排序。
  • 在實際應用中經常需要對查詢結果進行排序,比如,在網上購物時,可以将商品按照價格進行排序;在醫院的挂号系統中,可以按照挂号的先後順序進行排序等。
  • ORDER BY 關鍵字主要用來将查詢結果中的資料按照一定的順序進行排序,其文法格式如下:
ORDER BY <字段名> [ASC|DESC]           

複制

  • 文法說明如下。
  1. 字段名:表示需要排序的字段名稱,多個字段時用逗号隔開。
  2. ASC|DESC:ASC表示字段按升序排序;DESC表示字段按降序排序。其中ASC為預設值。
  3. DESC是從大到小,ASC是從小到大
  • 使用 ORDER BY 關鍵字應該注意以下幾個方面:
  1. ORDER BY 關鍵字後可以跟子查詢(關于子查詢後面教程會詳細講解,這裡了解即可)。
  2. 當排序的字段中存在空值時,ORDER BY 會将該空值作為最小值來對待。
  3. ORDER BY 指定多個字段進行排序時,MySQL 會按照字段的順序從左到右依次進行排序。

1. 單字段排序

  • 查詢history表的資料,clock字段按降序排序(也就是從大到小,從最新到最舊的時間),并且分頁顯示,從0開始顯示,每頁顯示10條記錄,目前顯示第1頁
  • 下面的例子就是取目前最新時間的10條曆史資料
  • 那麼,經曆了這些操作階段:先查詢、再排序、後分頁
mysql> select FROM_UNIXTIME(his.clock),his.value from history as his order by his.clock desc limit 0,10;
+--------------------------+---------------------+
| FROM_UNIXTIME(his.clock) | value               |
+--------------------------+---------------------+
| 2022-03-23 11:39:58      | 0.03327262491210712 |
| 2022-03-23 11:39:57      |  0.2994525692658531 |
| 2022-03-23 11:39:57      |     6.7543337663136 |
| 2022-03-23 11:39:56      |   6.937363366354516 |
| 2022-03-23 11:39:56      |  1.0364532470703125 |
| 2022-03-23 11:39:56      |   2.312458609154667 |
| 2022-03-23 11:39:56      | 0.24791898308140758 |
| 2022-03-23 11:39:55      |  2.2958371233088815 |
| 2022-03-23 11:39:55      |  0.3120714025473114 |
| 2022-03-23 11:39:55      |                   0 |
+--------------------------+---------------------+
10 rows in set (0.15 sec)

mysql>            

複制

2. 多字段排序

  • ORDER BY 指定多個字段進行排序時,MySQL 會按照字段的順序從左到右依次進行排序。

2.1 下面的案例,查詢 history 表中的 clock 和 value 字段,先按 clock 排序,再按 value 排序,SQL 語句和運作結果如下。

mysql> select FROM_UNIXTIME(his.clock),his.value from history as his order by his.clock,his.value desc limit 0,10;
+--------------------------+-------------------+
| FROM_UNIXTIME(his.clock) | value             |
+--------------------------+-------------------+
| 2022-03-16 21:46:16      |         96.085049 |
| 2022-03-16 21:46:16      | 3.914951000000002 |
| 2022-03-16 21:46:16      |          2.126223 |
| 2022-03-16 21:46:16      |          0.978738 |
| 2022-03-16 21:46:16      |          0.759366 |
| 2022-03-16 21:46:16      |              0.18 |
| 2022-03-16 21:46:16      |              0.09 |
| 2022-03-16 21:46:16      |              0.07 |
| 2022-03-16 21:46:16      |          0.050624 |
| 2022-03-16 21:46:16      |                 0 |
+--------------------------+-------------------+
10 rows in set (0.17 sec)           

複制

注意:在對多個字段進行排序時,排序的第一個字段必須有相同的值,才會對第二個字段進行排序。如果第一個字段資料中所有的值都是唯一的,MySQL 将不再對第二個字段進行排序。

2.2 下面的案例,clock字段按desc降序排序,value字段按asc升序排序

select FROM_UNIXTIME(his.clock),his.value from history as his order by his.clock desc,his.value asc limit 0,100;           

複制

條件查詢

  • 查詢條件可以是:
  1. 帶比較運算符和邏輯運算符的查詢條件
  2. 帶 BETWEEN AND 關鍵字的查詢條件
  3. 帶 IS NULL 關鍵字的查詢條件
  4. 帶 IN 關鍵字的查詢條件
  5. 帶 LIKE 關鍵字的查詢條件

1. 單一條件的查詢語句

  • 單一條件指的是在 WHERE 關鍵字後隻有一個查詢條件。
# 按clock字段從最新到最舊的時間進行排序,并顯示前10行記錄
mysql> select from_unixtime(his.clock), his.value from zabbix.history as his order by his.clock desc limit 10;
+--------------------------+---------------------+
| from_unixtime(his.clock) | value               |
+--------------------------+---------------------+
| 2022-03-23 15:28:28      | 0.08122102270804427 |
| 2022-03-23 15:28:28      | 0.31311299809630666 |
| 2022-03-23 15:28:27      |                 100 |
| 2022-03-23 15:28:27      |                   0 |
| 2022-03-23 15:28:27      |  0.7355883252732085 |
| 2022-03-23 15:28:26      |                   0 |
| 2022-03-23 15:28:26      |                   0 |
| 2022-03-23 15:28:26      |           15.969782 |
| 2022-03-23 15:28:25      |            0.007042 |
| 2022-03-23 15:28:24      |            9.618901 |
+--------------------------+---------------------+
10 rows in set (0.16 sec)           

複制

2. 多條件的查詢語句

在 WHERE 關鍵詞後可以有多個查詢條件,這樣能夠使查詢結果更加精确。多個查詢條件時用邏輯運算符 AND(&&)、OR(||)或 XOR 隔開。

  • AND:記錄滿足所有查詢條件時,才會被查詢出來。
  • OR:記錄滿足任意一個查詢條件時,才會被查詢出來。
  • XOR:記錄滿足其中一個條件,并且不滿足另一個條件時,才會被查詢出來。
# 在 events 表中查詢 eventid 大于 400,并且 objectid 大于等于 16274 的事件資訊,SQL 語句和運作結果如下。
mysql> select eventid,objectid,name from zabbix.events where eventid>400 and objectid>=16274; 
+---------+----------+------------------------------------------------------------------+
| eventid | objectid | name                                                             |
+---------+----------+------------------------------------------------------------------+
|     429 |    17775 | More than 100 items having missing data for more than 10 minutes |
+---------+----------+------------------------------------------------------------------+
1 row in set (0.00 sec)

# 在 events 表中查詢 eventid 大于 400,并且 objectid 大于等于 15000 的事件資訊,SQL 語句和運作結果如下。
mysql> select eventid,objectid,name from zabbix.events where eventid>400 and objectid>=15000;
+---------+----------+------------------------------------------------------------------+
| eventid | objectid | name                                                             |
+---------+----------+------------------------------------------------------------------+
|     429 |    17775 | More than 100 items having missing data for more than 10 minutes |
+---------+----------+------------------------------------------------------------------+
1 row in set (0.00 sec)           

複制

OR、AND 和 XOR 可以一起使用,但是在使用時要注意運算符的優先級

查詢條件越多,查詢出來的記錄就會越少。因為,設定的條件越多,查詢語句的限制就更多,能夠滿足所有條件的記錄就更少。為了使查詢出來的記錄正是自己想要的,可以在 WHERE 語句中将查詢條件設定的更加具體。

模糊查詢

在 MySQL 中,LIKE 關鍵字主要用于搜尋比對字段中的指定内容。其文法格式如下:

[NOT] LIKE  '字元串'           

複制

其中:

  • NOT :可選參數,字段中的内容與指定的字元串不比對時滿足條件。
  • 字元串:指定用來比對的字元串。“字元串”可以是一個很完整的字元串,也可以包含通配符。

在 where like 的條件查詢中,SQL 提供了四種比對方式。

  • “%”通配符:表示任意 0 個或多個字元。可比對任意類型和長度的字元,有些情況下若是中文,請使用兩個百分号(%%)表示。
  • ”_“通配符:隻能代表單個字元,字元的長度不能為 0。例如,a_b可以代表 acb、adb、aub 等字元串。
  • “:”通配符:表示任意單個字元。比對單個任意字元,它常用來限制表達式的字元長度語句。
  • “[]”通配符:表示括号内所列字元中的一個(類似正規表達式)。指定一個字元、字元串或範圍,要求所比對對象為它們中的任一個。
  • “[^]”通配符 :表示不在括号所列之内的單個字元。其取值和 [] 相同,但它要求所比對對象為指定字元以外的任一個字元。
查詢内容包含通配符時,由于通配符的緣故,導緻我們查詢特殊字元 “%”、“”、“[” 的語句無法正常實作,而把特殊字元用 “[ ]” 括起便可正常查詢。

通配符是一種特殊語句,主要用來模糊查詢。當不知道真正字元或者懶得輸入完整名稱時,可以使用通配符來代替一個或多個真正的字元。

1. 帶有“%”通配符的查詢

%”是 MySQL 中最常用的通配符,它能代表任何長度的字元串,字元串的長度可以為 0。例如,a%b表示以字母 a 開頭,以字母 b 結尾的任意長度的字元串。該字元串可以代表 ab、acb、accb、accrb 等字元串。有些情況下若是中文,請使用兩個百分号(%%)表示。

案例:從hosts表中的name字段查找所有以“T”開頭的記錄

mysql> select name from zabbix.hosts where name like 'T%';
+-----------------------------------------------------------------------------+
| name                                                                        |
+-----------------------------------------------------------------------------+
| Template APP Apache Kafka by JMX                                            |
| Template App Apache Tomcat JMX                                              |
| Template App Apache by HTTP                                                 |
| Template App Apache by Zabbix agent                                         |
| Template App Ceph by Zabbix Agent2                                          |           

複制

注意:比對的字元串必須加單引号或雙引号。

案例:從hosts表中的name字段查找所有不以“T”開頭的記錄

mysql> select name from zabbix.hosts where name not like 'T%';
+--------------+
| name         |
+--------------+
| mysql-db02   |
| mysql-master |
| zbxproxy01   |
| zbxproxy02   |
| zbxproxy03   |
| zbxproxy04   |
| zbxser01     |
| zbxser02     |           

複制

案例:從hosts表中的name字段查找包含有CPU的記錄

mysql> select name from zabbix.hosts where name like '%CPU%';
+----------------------------------------------------+
| name                                               |
+----------------------------------------------------+
| Template Module Cisco OLD-CISCO-CPU-MIB SNMP       |
| Template Module HOST-RESOURCES-MIB CPU SNMP        |
| Template Module Linux CPU SNMP                     |
| Template Module Linux CPU by Zabbix agent          |
| Template Module Linux CPU by Zabbix agent active   |
| Template Module Windows CPU by Zabbix agent        |
| Template Module Windows CPU by Zabbix agent active |
+----------------------------------------------------+
7 rows in set (0.00 sec)           

複制

2. 帶有“_”通配符的查詢

“_”隻能代表單個字元,字元的長度不能為 0。例如,a_b可以代表 acb、adb、aub 等字元串。 案例:在 hosts 表中,查找所有以數字“01”結尾,且“01”前面隻有 6 個字元的名稱,SQL 語句和運作結果如下。

mysql> select name,status from zabbix.hosts where status=0 and name like '______01';
+----------+--------+
| name     | status |
+----------+--------+
| zbxser01 |      0 |
+----------+--------+
1 row in set (0.00 sec)           

複制

3. LIKE區分大小寫

預設情況下,LIKE 關鍵字比對字元的時候是不區分大小寫的。如果需要區分大小寫,可以加入 BINARY 關鍵字。

# 比對t開頭的行記錄,并區分大小寫
mysql> select name,status from zabbix.hosts where name like binary 't%';
Empty set, 1 warning (0.00 sec)           

複制

注意:mysql8貌似已經廢除了該特性,mysql5是可以的

4. 使用通配符的注意事項和技巧

下面是使用通配符的一些注意事項:

  • 注意大小寫。MySQL 預設是不區分大小寫的。如果區分大小寫,像“Tom”這樣的資料就不能被“t%”所比對到。
  • 注意尾部空格,尾部空格會幹擾通配符的比對。例如,“T% ”就不能比對到“Tom”。
  • 注意 NULL。“%”通配符可以比對到任意字元,但是不能比對 NULL。也就是說 “%”比對不到某資料表中值為 NULL 的記錄。

下面是一些使用通配符要記住的技巧。

  • 不要過度使用通配符,如果其它操作符能達到相同的目的,應該使用其它操作符。因為 MySQL 對通配符的處理一般會比其他操作符花費更長的時間。
  • 在确定使用通配符後,除非絕對有必要,否則不要把它們用在字元串的開始處。把通配符置于搜尋模式的開始處,搜尋起來是最慢的。
  • 仔細注意通配符的位置。如果放錯地方,可能不會傳回想要的資料。
  • 如果查詢内容中包含通配符,可以使用“\”轉義符
總之,通配符是一種極其重要和有用的搜尋工具,以後我們會經常用到它。

範圍查詢

MySQL 提供了 BETWEEN AND 關鍵字,用來判斷字段的數值是否在指定範圍内。 BETWEEN AND 需要兩個參數,即範圍的起始值和終止值。如果字段值在指定的範圍内,則這些記錄被傳回。如果不在指定範圍内,則不會被傳回。 使用 BETWEEN AND 的基本文法格式如下:

[NOT] BETWEEN 取值1 AND 取值2           

複制

  • NOT:可選參數,表示指定範圍之外的值。如果字段值不滿足指定範圍内的值,則這些記錄被傳回。
  • 取值1:表示範圍的起始值。
  • 取值2:表示範圍的終止值。

案例:查詢2022年3月23号上午10點到11點這個時間段的曆史資料

# 确定起始時間和結束時間的時間戳
mysql> select itemid,from_unixtime(clock),clock,value,ns from zabbix.history where from_unixtime(clock) like '2022-03-23 10:00:02%';
+--------+----------------------+------------+-------+-----------+
| itemid | from_unixtime(clock) | clock      | value | ns        |
+--------+----------------------+------------+-------+-----------+
|  29162 | 2022-03-23 10:00:02  | 1648000802 |     0 | 277202868 | # 起始時間
+--------+----------------------+------------+-------+-----------+
1 row in set (0.70 sec)

mysql> 
mysql> select itemid,from_unixtime(clock),clock,value,ns from zabbix.history where from_unixtime(clock) like '2022-03-23 11:00:01%';
+--------+----------------------+------------+-----------+----------+
| itemid | from_unixtime(clock) | clock      | value     | ns       |
+--------+----------------------+------------+-----------+----------+
|  33064 | 2022-03-23 11:00:01  | 1648004401 | 87.926269 | 39923084 | # 結束時間
+--------+----------------------+------------+-----------+----------+
1 row in set (0.76 sec)

mysql> 

# 通過BETWEEN AND 關鍵字來做範圍查詢,語句如下
mysql> select itemid,from_unixtime(clock),clock,value,ns from zabbix.history where clock BETWEEN 1648000802 AND 1648004401;           

複制

空值查詢

MySQL 提供了 IS NULL 關鍵字,用來判斷字段的值是否為空值(NULL)。空值不同于 0,也不同于空字元串。如果字段的值是空值,則滿足查詢條件,該記錄将被查詢出來。如果字段的值不是空值,則不滿足查詢條件。使用 IS NULL 的基本文法格式如下:

IS [NOT] NULL           

複制

  • 其中,“NOT”是可選參數,表示字段值不是空值時滿足條件。

案例:使用 IS NULL 關鍵字來查詢 users 表中 url 字段是 NULL 的記錄。

select * from zabbix.users where url not null;           

複制

案例:使用 IS NULL 關鍵字來查詢 users 表中 url 字段是 不為NULL 的記錄。

select * from zabbix.users where url is not null;           

複制

注意:IS NULL 是一個整體,不能将 IS 換成“=”。如果将 IS 換成“=”将不能查詢出任何結果,資料庫系統會出現“Empty set(0.00 sec)”這樣的提示。同理,IS NOT NULL 中的 IS NOT 不能換成“!=”或“<>”。

分組查詢(重要&常用)

  • 分組查詢的作用是将查詢的結果按指定字段分組,字段中數值相等的為一組。 分組以後可以配合count()、agv()、sum()、max()等聚合函數使用。
  • Group by 語句用于結合聚合函數(如count,sum,avg,max,min),根據一個或多個列對結果集進行分組。
  • MySQL 8.0開始 group by 預設是沒有排序的,那MySQL 8.0之前和 8.0 就有可能結果出現不同 需要警惕

9.1 GROUP BY單獨使用

案例:查詢每台主機有多少台

# 查詢每台主機名稱有多少台
mysql> select name "主機名",count(*) "數量"  from zabbix.hosts where status=0 and name not like '%{%' group by name; 
+--------------+--------+
| 主機名       | 數量   |
+--------------+--------+
| zbxser01     |      1 |
| mysql-master |      1 |
| mysql-db02   |      1 |
| zbxser02     |      1 |
| zbxproxy01   |      1 |
| zbxproxy02   |      1 |
| zbxproxy04   |      1 |
| zbxproxy03   |      1 |
+--------------+--------+
8 rows in set (0.00 sec)           

複制

9.2 GROUP BY 與 GROUP_CONCAT()

GROUP BY 關鍵字可以和 GROUP_CONCAT() 函數一起使用。GROUP_CONCAT() 函數會把每個分組的字段值都顯示出來。

案例:根據 hosts 表中的 STATUS 字段進行分組查詢,使用 GROUP_CONCAT() 函數将每個分組的 NAME 字段的值都顯示出來,需要知道每個狀态都對應哪些名稱的時候,就很有用了

SELECT STATUS,GROUP_CONCAT(NAME) FROM zabbix.hosts WHERE STATUS!=5 GROUP BY STATUS;           

複制

一文帶你剖析MySQL到底都有哪些常用的查詢去重(過濾重複資料)别名分頁查詢(限制查詢結果的條數)排序(對查詢結果排序)條件查詢模糊查詢範圍查詢空值查詢分組查詢(重要&amp;常用)過濾分組
由結果可以看到,查詢結果分為兩組,status 字段值為“0”的是一組,值為“3”的是一組,且每組的主機名或者模闆名稱都顯示出來了。

9.3 GROUP BY 與聚合函數

在資料統計時,GROUP BY 關鍵字經常和聚合函數一起使用。 聚合函數包括 COUNT(),SUM(),AVG(),MAX() 和 MIN()。其中,COUNT() 用來統計記錄的條數;SUM() 用來計算字段值的總和;AVG() 用來計算字段值的平均值;MAX() 用來查詢字段的最大值;MIN() 用來查詢字段的最小值。

案例:根據 hosts 表的 name 字段進行分組查詢,使用 COUNT() 函數計算每一組的記錄數

mysql> select name,count(name) from zabbix.hosts where status=0 and name not like '%{%' group by name;
+--------------+-------------+
| name         | count(name) |
+--------------+-------------+
| zbxser01     |           1 |
| mysql-master |           1 |
| mysql-db02   |           1 |
| zbxser02     |           1 |
| zbxproxy01   |           1 |
| zbxproxy02   |           1 |
| zbxproxy04   |           1 |
| zbxproxy03   |           1 |
+--------------+-------------+           

複制

9.4 GROUP BY 與 WITH ROLLUP

WITH ROLLUP 關鍵字用來在所有記錄的最後加上一條記錄,這條記錄是上面所有記錄的總和,即統計記錄數量。

案例:根據 hosts 表中的 name 字段進行分組查詢,并使用 WITH ROLLUP 顯示記錄的總和

mysql> select name,count(name) from zabbix.hosts where status=0 and name not like '%{%' group by name with rollup; 
+--------------+-------------+
| name         | count(name) |
+--------------+-------------+
| mysql-db02   |           1 |
| mysql-master |           1 |
| zbxproxy01   |           1 |
| zbxproxy02   |           1 |
| zbxproxy03   |           1 |
| zbxproxy04   |           1 |
| zbxser01     |           1 |
| zbxser02     |           1 |
| NULL         |           8 | # 這裡就是通過with rollup關鍵字計算出來的總和           

複制

過濾分組

在 MySQL 中,可以使用 HAVING 關鍵字對分組後的資料進行過濾。 HAVING 關鍵字和 WHERE 關鍵字都可以用來過濾資料,且 HAVING 支援 WHERE 關鍵字中所有的操作符和文法。 但是 WHERE 和 HAVING 關鍵字也存在以下幾點差異:
  • 一般情況下,WHERE 用于過濾資料行,而 HAVING 用于過濾分組。
  • WHERE 查詢條件中不可以使用聚合函數,而 HAVING 查詢條件中可以使用聚合函數。
  • WHERE 在資料分組前進行過濾,而 HAVING 在資料分組後進行過濾 。
  • WHERE 針對資料庫檔案進行過濾,而 HAVING 針對查詢結果進行過濾。也就是說,WHERE 根據資料表中的字段直接進行過濾,而 HAVING 是根據前面已經查詢出的字段進行過濾。
  • WHERE 查詢條件中不可以使用字段别名,而 HAVING 查詢條件中可以使用字段别名。

案例:了解 WHERE 和 HAVING 關鍵字的相同點和不同點,分别使用 HAVING 和 WHERE 關鍵字查詢出 hosts 表中的name、host、status。SQL 語句和運作結果如下。

# SELECT 關鍵字後已經查詢出了 status 字段,是以 HAVING可用
mysql> select name,host,status from zabbix.hosts having status=0;
+--------------+--------------+--------+
| name         | host         | status |
+--------------+--------------+--------+
| zbxser01     | zbxser01     |      0 |
| {#HV.NAME}   | {#HV.UUID}   |      0 |
| {#VM.NAME}   | {#VM.UUID}   |      0 |
| mysql-master | mysql-master |      0 |
| mysql-db02   | mysql-db02   |      0 |
| zbxser02     | zbxser02     |      0 |
| zbxproxy01   | zbxproxy01   |      0 |
| zbxproxy02   | zbxproxy02   |      0 |
| zbxproxy04   | zbxproxy04   |      0 |
| zbxproxy03   | zbxproxy03   |      0 |
+--------------+--------------+--------+
10 rows in set (0.00 sec)

# SELECT 關鍵字後沒有 status 字段,是以 HAVING報錯了
mysql> select name,host from zabbix.hosts having status=0;        
ERROR 1054 (42S22): Unknown column 'status' in 'having clause'
mysql> 

# SELECT 關鍵字後沒有 status 字段,where是OK的
mysql> select name,host from zabbix.hosts where status=0;      
+--------------+--------------+
| name         | host         |
+--------------+--------------+
| zbxser01     | zbxser01     |
| {#HV.NAME}   | {#HV.UUID}   |
| {#VM.NAME}   | {#VM.UUID}   |
| mysql-master | mysql-master |
| mysql-db02   | mysql-db02   |
| zbxser02     | zbxser02     |
| zbxproxy01   | zbxproxy01   |
| zbxproxy02   | zbxproxy02   |
| zbxproxy04   | zbxproxy04   |
| zbxproxy03   | zbxproxy03   |
+--------------+--------------+
10 rows in set (0.00 sec)

mysql>            

複制

因為在 SELECT 關鍵字後已經查詢出了 status 字段,是以 HAVING 和 WHERE 都可以使用。但是如果 SELECT 關鍵字後沒有查詢出 status 字段,這時的having就會報錯,where是OK的。 由結果可以看出,如果 SELECT 關鍵字後沒有查詢出 HAVING 查詢條件中使用的 status 字段,MySQL 會提示錯誤資訊:“having子句”中的列“status”未知”。

案例:使用 HAVING 和 WHERE 關鍵字分别查詢status等于0的結果

# 根據hosts表中的status字段進行分組,并通過group_concat将每個分組字段name的内容顯示出來,查詢全量,不過濾
mysql> select status,group_concat(name) from zabbix.hosts group by status\G;        
*************************** 1. row ***************************
            status: 0
group_concat(name): zbxser01,{#HV.NAME},{#VM.NAME},mysql-master,mysql-db02,zbxser02,zbxproxy01,zbxproxy02,zbxproxy04,zbxproxy03
*************************** 2. row ***************************
            status: 3
group_concat(name): Template OS Linux by Zabbix agent,Template App Zabbix Server,Template App Zabbix Proxy,Template Module Zabbix agent,Template OS OpenBSD,Template OS FreeBSD,Template OS AIX,Template OS HP-UX,Template OS Solaris,Template OS Mac OS X,Template OS Windows by Zabbix agent,Template App FTP Service,Template App HTTP Service,Template App HTTPS Service,Template App IMAP Service,Template App LDAP Service,Template App NNTP Service,Template App NTP Service,Template App POP Service,Template App SMTP Service,Template App SSH Service,Template App Telnet Service,Template App Generic Java JMX,Template DB MySQL,Template Server Intel SR1530 IPMI,Template Server Intel SR1630 IPMI,Template VM VMware,Template VM VMware Guest,Template VM VMware Hypervisor,Template Module EtherLike-MIB SNMP,Template Module HOST-RESOURCES-MIB SNMP,Template Module ICMP Ping,Template Module Interfaces Simple SNMP,Template Module Interfaces SNMP,Template Module Interfaces Windows SNMP,Template Module Generic SNMP,Template Net Alcatel Timetra TiMOS SNMP,T
*************************** 3. row ***************************
            status: 5
group_concat(name): ,,,
3 rows in set, 1 warning (0.00 sec)

ERROR: 
No query specified

mysql> 

# 根據hosts表中的status字段進行分組,并通過group_concat将每個分組字段name的内容顯示出來,通過having關鍵字過濾為0的結果
mysql> select status,group_concat(name) from zabbix.hosts group by status having status=0;
+--------+-------------------------------------------------------------------------------------------------------------+
| status | group_concat(name)                                                                                          |
+--------+-------------------------------------------------------------------------------------------------------------+
|      0 | zbxser01,{#HV.NAME},{#VM.NAME},mysql-master,mysql-db02,zbxser02,zbxproxy01,zbxproxy02,zbxproxy04,zbxproxy03 |
+--------+-------------------------------------------------------------------------------------------------------------+
1 row in set, 1 warning (0.01 sec)

# 根據hosts表中的status字段進行分組,并通過group_concat将每個分組字段name的内容顯示出來,通過where關鍵字過濾為0的結果
mysql> select status,group_concat(name) from zabbix.hosts where status=0 group by status;
+--------+-------------------------------------------------------------------------------------------------------------+
| status | group_concat(name)                                                                                          |
+--------+-------------------------------------------------------------------------------------------------------------+
|      0 | zbxser01,{#HV.NAME},{#VM.NAME},mysql-master,mysql-db02,zbxser02,zbxproxy01,zbxproxy02,zbxproxy04,zbxproxy03 |
+--------+-------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)           

複制

本文轉載于彩虹運維技術棧社群:

https://mp.weixin.qq.com/s/mLerKP2f--8jQjpHuM3ZkQ