欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL?where和having的異同

 更新時間:2024年02月07日 08:32:12   作者:安然無虞  
我們在進行查詢的時候,經(jīng)常需要按照條件對查詢結(jié)果進行篩選,這就要用到條件語句where和having了,本文主要介紹了MySQL?where和having的異同,具有一定的參考價值,感興趣的可以了解一下

我們在進行查詢的時候,經(jīng)常需要按照條件對查詢結(jié)果進行篩選,這就要用到條件語句where和having了。

where是直接對表中的字段進行限定來篩選結(jié)果,having則需要跟分組關(guān)鍵字group by一起使用,通過對分組字段或分組計算函數(shù)進行限定來篩選結(jié)果。雖然它們都是對查詢進行限定,卻有著各自的特點和適用場景。很多時候,我們會遇到2個都可以用的情況。一旦用錯,就容易出現(xiàn)執(zhí)行效率低下、查詢結(jié)果錯誤,甚至是查詢無法運行的情況。

一個實際查詢需求

超市經(jīng)營者提出,要查單筆銷售金額超過50元的商品。

我們來分析一下這個需求:需要查詢出一個商品記錄集,限定條件是單筆銷售超過50元。這個時候,我們就需要用到where 和 having了。

這個問題的條件很明確,查詢的結(jié)果也只有“商品”一個字段,看起來挺容易實現(xiàn)的。

假設(shè)我們有一個商品信息表demo.goodsmaster,里面有2種商品:書和筆。

mysql> select *
    -> from demo.goodsmaster;
+------------+---------+-----------+---------------+------+------------+
| itemnumber | barcode | goodsname | specification | unit | salesprice |
+------------+---------+-----------+---------------+------+------------+
|          1 | 0001    | 書        |               | 本   |      89.00 |
|          2 | 0002    | 筆        |               | 支   |       5.00 |
+------------+---------+-----------+---------------+------+------------+
2 rows in set (0.00 sec)

同時我們還有一個商品銷售明細表demo.transactiondetails,里面有4條銷售記錄:

mysql> select *
    -> from demo.transactiondetails;
+---------------+------------+----------+-------+------------+
| transactionid | itemnumber | quantity | price | salesvalue |
+---------------+------------+----------+-------+------------+
|             1 |          1 |    1.000 | 89.00 |      89.00 |
|             1 |          2 |    2.000 |  5.00 |      10.00 |
|             2 |          1 |    2.000 | 89.00 |     178.00 |
|             3 |          2 |   10.000 |  5.00 |      50.00 |
+---------------+------------+----------+-------+------------+
4 rows in set (0.01 sec)

接下來我們分別用where和having盡心查詢,看看它們各自是如何查詢的,是否能夠得到正確的結(jié)果。

首先用where關(guān)鍵字進行查詢:

mysql> select distinct b.goodsname
-> from demo.transactiondetails as a
-> join demo.goodsmaster as b
-> on (a.itemnumber=b.itemnumber)
-> where a.salesvalue > 50;
+-----------+
| goodsname |
+-----------+
| 書 |
+-----------+
1 row in set (0.00 sec)

接著,使用having 關(guān)鍵字進行查詢:

mysql> select b.goodsname
-> from demo.transactiondetails as a
-> join demo.goodsmaster as b
-> on (a.itemnumber = b.itemnumber)
-> group by b.goodsname
-> having max(a.salesvalue) > 50;
+-----------+
| goodsname |
+-----------+
| 書 |
+-----------+
1 row in set (0.00 sec)

可以看到兩次查詢的結(jié)果是一樣的,那么這兩種查詢到底有什么區(qū)別,那個更好呢?要明白這個問題,首先我們需要先學(xué)習(xí)where和having的執(zhí)行過程。

where

我們先來分析一下剛才使用 where 條件的查詢語句,來看看 MySQL 是如何執(zhí)行這個查詢的。

首先,MySQL 從數(shù)據(jù)表 demo.transactiondetails 中抽取滿足條件“a.salesvalue>50”的記錄:

mysql> select *
    -> from demo.transactiondetails as a
    -> where a.salesvalue > 50;
+---------------+------------+----------+-------+------------+
| transactionid | itemnumber | quantity | price | salesvalue |
+---------------+------------+----------+-------+------------+
|             1 |          1 |    1.000 | 89.00 |      89.00 |
|             2 |          1 |    2.000 | 89.00 |     178.00 |
+---------------+------------+----------+-------+------------+
2 rows in set (0.00 sec)

為了獲取到銷售信息所對應(yīng)的商品名稱,我們需要通過公共字段“itemnumber”與數(shù)據(jù)表 demo.goodsmaster 進行關(guān)聯(lián),從 demo.goodsmaster 中獲取商品名稱:

mysql> select
    ->     a.*, b.goodsname
    -> from
    ->     demo.transactiondetails a
    -> join
    ->     demo.goodsmaster b 
    -> on (a.itemnumber = b.itemnumber)
    -> where
    ->     a.salesvalue > 50;
+---------------+------------+----------+-------+------------+-----------+
| transactionid | itemnumber | quantity | price | salesvalue | goodsname |
+---------------+------------+----------+-------+------------+-----------+
|             1 |          1 |    1.000 | 89.00 |      89.00 | 書        |
|             2 |          1 |    2.000 | 89.00 |     178.00 | 書        |
+---------------+------------+----------+-------+------------+-----------+
2 rows in set (0.00 sec)

這個時候,如果查詢商品名稱,就會出現(xiàn)兩個重復(fù)的記錄:

mysql> select
    ->     b.goodsname
    -> from
    ->     demo.transactiondetails as a
    -> join
    ->     demo.goodsmaster as b on (a.itemnumber = b.itemnumber)
    -> where
    ->     a.salesvalue > 50;
+-----------+
| goodsname |
+-----------+
| 書        |
| 書        |
+-----------+
2 rows in set (0.00 sec)

需要注意的是,為了消除重復(fù)的語句,這里我們需要用到一個關(guān)鍵字:DISTINCT,它的作用是返回唯一不同的值。比如,DISTINCT 字段 1,就表示返回所有字段 1 的不同的值。

下面我們嘗試一下加上 DISTINCT 關(guān)鍵字的查詢:

mysql> select
    ->     distinct(b.goodsname)  -- 返回唯一不同的值
    -> from
    ->     demo.transactiondetails as a
    ->         join
    ->     demo.goodsmaster as b on (a.itemnumber = b.itemnumber)
    -> where
    ->     a.salesvalue > 50;
+-----------+
| goodsname |
+-----------+
| 書        |
+-----------+
1 row in set (0.00 sec)

這樣,我們就得到了需要的結(jié)果:單筆銷售金額超過 50 元的商品就是“書”。

總之,WHERE 關(guān)鍵字的特點是,直接用表的字段對數(shù)據(jù)集進行篩選。如果需要通過關(guān)聯(lián)查詢從其他的表獲取需要的信息,那么執(zhí)行的時候,也是先通過 WHERE 條件進行篩選,用篩選后的比較小的數(shù)據(jù)集進行連接。這樣一來,連接過程中占用的資源比較少,執(zhí)行效率也比較高。

having

講完了where,我們再說說having 是如何執(zhí)行的。不過,在這之前,我們先來了解一下group by,因為having不能單獨使用,必須要跟group by一起使用。

我們可以把group by 理解成對數(shù)據(jù)進行分組,方便我們對組內(nèi)的數(shù)據(jù)進行統(tǒng)計計算。

舉個小例子,來具體講講group by 如何使用,以及如何在分組里面進行統(tǒng)計計算。

假設(shè)現(xiàn)在有一組銷售數(shù)據(jù),我們需要從里面查詢每天、每個收銀員的銷售數(shù)量和銷售金額。我們通過以下的代碼,來查看一下數(shù)據(jù)的內(nèi)容:

mysql> select *
    -> from demo.transactionhead;
+---------------+------------------+------------+---------------------+
| transactionid | transactionno    | operatorid | transdate           |
+---------------+------------------+------------+---------------------+
|             1 | 0120201201000001 |          1 | 2020-12-10 00:00:00 |
|             2 | 0120201202000001 |          2 | 2020-12-11 00:00:00 |
|             3 | 0120201202000002 |          2 | 2020-12-12 00:00:00 |
+---------------+------------------+------------+---------------------+
3 rows in set (0.00 sec)

mysql> select *
    -> from demo.transactiondetails;
+---------------+------------+----------+-------+------------+
| transactionid | itemnumber | quantity | price | salesvalue |
+---------------+------------+----------+-------+------------+
|             1 |          1 |    1.000 | 89.00 |      89.00 |
|             1 |          2 |    2.000 |  5.00 |      10.00 |
|             2 |          1 |    2.000 | 89.00 |     178.00 |
|             3 |          2 |   10.000 |  5.00 |      50.00 |
+---------------+------------+----------+-------+------------+
4 rows in set (0.01 sec)

mysql> select *
    -> from demo.operator;
+------------+----------+--------+--------------+-------------+---------+--------------------+--------+
| operatorid | branchid | workno | operatorname | phone       | address | pid                | duty   |
+------------+----------+--------+--------------+-------------+---------+--------------------+--------+
|          1 |        1 | 001    | 張靜         | 18612345678 | 北京    | 110392197501012332 | 店長   |
|          2 |        1 | 002    | 李靜        | 13312345678 | 北京    | 110222199501012332 | 收銀員 |
+------------+----------+--------+--------------+-------------+---------+--------------------+--------+
2 rows in set (0.01 sec)

mysql> select
    -> a.transdate,   -- 交易時間
    -> c.operatorname,-- 操作員
    -> d.goodsname,   -- 商品名稱
    -> b.quantity,    -- 銷售數(shù)量
    -> b.price,       -- 價格
    -> b.salesvalue   -- 銷售金額
    -> from
    ->   demo.transactionhead as a
    -> join
    ->   demo.transactiondetails as b on (a.transactionid = b.transactionid)
    -> join
    ->  demo.operator as c on (a.operatorid = c.operatorid)
    -> join
    ->  demo.goodsmaster as d on (b.itemnumber = d.itemnumber);
+---------------------+--------------+-----------+----------+-------+------------+
| transdate           | operatorname | goodsname | quantity | price | salesvalue |
+---------------------+--------------+-----------+----------+-------+------------+
| 2020-12-10 00:00:00 | 張靜         | 書        |    1.000 | 89.00 |      89.00 |
| 2020-12-10 00:00:00 | 張靜         | 筆        |    2.000 |  5.00 |      10.00 |
| 2020-12-11 00:00:00 | 李靜        | 書        |    2.000 | 89.00 |     178.00 |
| 2020-12-12 00:00:00 | 李靜        | 筆        |   10.000 |  5.00 |      50.00 |
+---------------------+--------------+-----------+----------+-------+------------+
4 rows in set (0.00 sec)

如果我想看看每天的銷售數(shù)量和銷售金額,可以按照一個字段transdate對數(shù)據(jù)進行分組和統(tǒng)計。

mysql> select
    -> a.transdate,
    -> sum(b.quantity), -- 統(tǒng)計分組的總計銷售數(shù)量
    -> sum(b.salesvalue) -- 統(tǒng)計分組的總計銷售金額
    -> from
    ->   demo.transactionhead as a
    -> join
    -> demo.transactiondetails as b on (a.transactionid = b.transactionid)
    -> group by a.transdate;
+---------------------+-----------------+-------------------+
| transdate           | SUM(b.quantity) | SUM(b.salesvalue) |
+---------------------+-----------------+-------------------+
| 2020-12-10 00:00:00 |           3.000 |             99.00 |
| 2020-12-11 00:00:00 |           2.000 |            178.00 |
| 2020-12-12 00:00:00 |          10.000 |             50.00 |
+---------------------+-----------------+-------------------+
3 rows in set (0.00 sec)

如果想看看每天、每個收銀員的銷售數(shù)量和銷售金額,可以按照2個字段進行分組和統(tǒng)計,分別是transdate和operatorname:

mysql>  select
    ->     a.transdate,
    ->     c.operatorname,
    ->     sum(b.quantity), -- 數(shù)量求和
    ->     sum(b.salesvalue)-- 金額求和
    -> from
    ->     demo.transactionhead as a
    -> join
    ->     demo.transactiondetails as b on (a.transactionid = b.transactionid)
    -> join
    ->     demo.operator as C on (a.operatorid = c.operatorid)
    -> group by a.transdate , c.operatorname; -- 按照交易日期和操作員分組
+---------------------+--------------+-----------------+-------------------+
| transdate           | operatorname | SUM(b.quantity) | SUM(b.salesvalue) |
+---------------------+--------------+-----------------+-------------------+
| 2020-12-10 00:00:00 | 張靜         |           3.000 |             99.00 |
| 2020-12-11 00:00:00 | 李靜        |           2.000 |            178.00 |
| 2020-12-12 00:00:00 | 李靜        |          10.000 |             50.00 |
+---------------------+--------------+-----------------+-------------------+
3 rows in set (0.00 sec)

可以看到,通過對銷售數(shù)據(jù)按照交易日期和收銀員進行分組,再對組內(nèi)數(shù)據(jù)進行求和統(tǒng)計,就實現(xiàn)了對每天、每個收銀員的銷售數(shù)量和銷售金額的查詢。

好了,知道了group by 的使用方法,我們就來學(xué)習(xí)having。

回到開頭的超市經(jīng)營者的需求:查詢單筆銷售金額超過 50 元的商品。現(xiàn)在我們來使用 having 來實現(xiàn),代碼如下:

mysql> select b.goodsname
    -> from demo.transactiondetails as a
    -> join demo.goodsmaster as b
    -> on (a.itemnumber=b.itemnumber)
    -> group by b.goodsname
    -> having max(a.salesvalue) > 50;
+-----------+
| goodsname |
+-----------+
| 書        |
+-----------+
1 row in set (0.00 sec)

這種查詢方式在MySQL里面分四步實現(xiàn)。

第一步,把流水明細表和商品信息表通過公共字段itemnumber連接起來,從兩個表中獲取數(shù)據(jù):

mysql> select
    ->     a.*, b.*
    -> from
    ->     demo.transactiondetails a
    ->         join
    ->     demo.goodsmaster b on (a.itemnumber = b.itemnumber);
+---------------+------------+----------+-------+------------+------------+---------+-----------+---------------+------+------------+
| transactionid | itemnumber | quantity | price | salesvalue | itemnumber | barcode | goodsname | specification | unit | salesprice |
+---------------+------------+----------+-------+------------+------------+---------+-----------+---------------+------+------------+
|             1 |          1 |    1.000 | 89.00 |      89.00 |          1 | 0001    | 書        | NULL          | 本   |      89.00 |
|             1 |          2 |    2.000 |  5.00 |      10.00 |          2 | 0002    | 筆        | NULL          | 支   |       5.00 |
|             2 |          1 |    2.000 | 89.00 |     178.00 |          1 | 0001    | 書        | NULL          | 本   |      89.00 |
|             3 |          2 |   10.000 |  5.00 |      50.00 |          2 | 0002    | 筆        | NULL          | 支   |       5.00 |
+---------------+------------+----------+-------+------------+------------+---------+-----------+---------------+------+------------+
4 rows in set (0.00 sec)

查詢的結(jié)果有點復(fù)雜,為了方便理解,對結(jié)果進行了分類,并加了注釋,如下圖所示:

img

第二步,把結(jié)果集按照商品名稱進行分組,分組的示意圖如下所示:

組一:

img

組二:

img

第三步,對分組后的數(shù)據(jù)集進行篩選,把組中字段salesvalue的最大值 >50 的組篩選出來,結(jié)果如下:

img

第四步,返回商品名稱。這是我們就得到了結(jié)果:單筆銷售金額超過50元的商品。

總結(jié)使用having的查詢過程:

首先我們需要把所有的信息都準備好,包括從關(guān)聯(lián)表中獲取的信息,對數(shù)據(jù)集進行分組,形成一個包含所有需要的信息的數(shù)據(jù)集合。接著,再通過having 條件篩選,得到需要的數(shù)據(jù)。

怎么正確的使用where和having?

首先我們需要知道它們的2個典型區(qū)別:

第一個區(qū)別是,如果需要通過連接從關(guān)聯(lián)表中獲取需要的數(shù)據(jù),where是先篩選后連接,而having是先連接后篩選。

這一點就決定了在關(guān)聯(lián)查詢中,where比having更高效。因為where可以先篩選,用一個篩選后的較小的數(shù)據(jù)集和關(guān)聯(lián)表進行連接,這樣占用的資源比較少,執(zhí)行效率也就比較高。having則需要先把結(jié)果集準備好,也就是用未被篩選的數(shù)據(jù)集進行關(guān)聯(lián),然后對這個大的數(shù)據(jù)集進行篩選,這樣占用的資源就比較多,執(zhí)行效率也比較低。

第二個區(qū)別是,where可以直接使用表中的字段作為篩選條件,但不能使用分組中的計算函數(shù)作為篩選條件;having必須要與group by配合使用,可以把分組計算的函數(shù)和分組字段作為篩選條件。

這也就決定了,在需要對數(shù)據(jù)進行分組統(tǒng)計的時候,having可以完成where不能完成的任務(wù)。這是因為,在查詢語法結(jié)構(gòu)中,where在group by 之前,所以無法對分組結(jié)果進行篩選。having在group by之后,可以使用分組字段和分組中的計算函數(shù)對分組的結(jié)果集進行篩選,這個功能是where無法完成的。

舉個例子,假如超市經(jīng)營者提出,要查詢是哪個收銀員、在哪天賣了2單商品。這種必須先分組才能篩選的查詢,用where語句實現(xiàn)就比較難,我們可能要分好幾步,通過把中間結(jié)果存儲起來,才能搞定,但是用having,就很輕松,如下:

mysql> select
    ->   a.transdate, c.operatorname
    -> from
    ->   demo.transactionhead as a
    -> join
    ->   demo.transactiondetails as b on (a.transactionid = b.transactionid)
    -> join
    ->   demo.operator as c on (a.operatorid = c.operatorid)
    -> group by a.transdate, c.operatorname
    -> having count(*)=2;  -- 銷售了2單
+---------------------+--------------+
| transdate           | operatorname |
+---------------------+--------------+
| 2020-12-10 00:00:00 | 張 靜        |
+---------------------+--------------+
1 row in set (0.01 sec)

where和having的優(yōu)缺點:

img

當(dāng)然了,where和having也可以一起配合使用,包含分組統(tǒng)計函數(shù)的條件用having,普通條件用where。這樣,我們就既利用了where條件的高效快速,又發(fā)揮了having可以使用包含分組統(tǒng)計函數(shù)的查詢條件的優(yōu)點,當(dāng)數(shù)據(jù)量特別大的時候,運行效率會有很大的差別。

相關(guān)文章

  • 快速實現(xiàn)MySQL的部署以及一機多實例部署

    快速實現(xiàn)MySQL的部署以及一機多實例部署

    這篇文章主要為大家詳細介紹了快速實現(xiàn)MySQL的部署以及一機多實例部署的相關(guān)資料,感興趣的小伙伴們可以參考一下
    2016-04-04
  • 如何用Navicat操作MySQL

    如何用Navicat操作MySQL

    這篇文章主要介紹了如何用Navicat操作MySQL,幫助大家使用可視化工具來連接 MySQL,感興趣的朋友可以了解下
    2021-05-05
  • Windows?本地安裝?Mysql8.0圖文教程

    Windows?本地安裝?Mysql8.0圖文教程

    本文介紹了如何在Windows本地安裝Mysql8.0。從下載Mysql8.0安裝包,運行安裝程序,配置初始設(shè)置到啟動Mysql服務(wù)等詳細步驟進行了講解。
    2023-04-04
  • MySQL字符集亂碼及解決方案分享

    MySQL字符集亂碼及解決方案分享

    這篇文章主要給大家介紹了關(guān)于MySQL字符集亂碼及解決方案的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • MySQL日期函數(shù)與時間函數(shù)匯總(MySQL 5.X)

    MySQL日期函數(shù)與時間函數(shù)匯總(MySQL 5.X)

    這篇文章主要給大家介紹了關(guān)于MySQL 5.X日期函數(shù)與時間函數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • SQL Server服務(wù)器監(jiān)控

    SQL Server服務(wù)器監(jiān)控

    這篇文章主要介紹了SQL Server服務(wù)器監(jiān)控,SQL server監(jiān)控是收集、聚合和監(jiān)控SQL服務(wù)器的各種指標的過程,更多相關(guān)內(nèi)容需要的朋友可以參考一下
    2022-09-09
  • MySQL索引知識的一些小妙招總結(jié)

    MySQL索引知識的一些小妙招總結(jié)

    這篇文章主要給大家總結(jié)介紹了關(guān)于MySQL索引知識的一些小妙招,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • Mysql8公用表表達式CTE詳解

    Mysql8公用表表達式CTE詳解

    這篇文章主要介紹了Mysql8公用表表達式CTE詳解,公用表表達式(或通用表表達式)簡稱為CTE,CTE可以理解成一個可以復(fù)用的子查詢,當(dāng)然跟子查詢還是有點區(qū)別的,CTE可以引用其他CTE,但子查詢不能引用其他子查詢,需要的朋友可以參考下
    2023-08-08
  • 使用mysqldump導(dǎo)出導(dǎo)入mysql表結(jié)構(gòu)或者數(shù)據(jù)

    使用mysqldump導(dǎo)出導(dǎo)入mysql表結(jié)構(gòu)或者數(shù)據(jù)

    這篇文章主要介紹了使用mysqldump導(dǎo)出導(dǎo)入mysql表結(jié)構(gòu)或者數(shù)據(jù)的相關(guān)資料,mysqldump是MySQL數(shù)據(jù)庫備份工具,用于導(dǎo)出數(shù)據(jù)和表結(jié)構(gòu),可以使用命令行工具運行該工具,并指定數(shù)據(jù)庫和表的名稱,導(dǎo)出的數(shù)據(jù)可以保存為SQL文件,需要的朋友可以參考下
    2024-12-12
  • MySQL錯誤代碼3140:無效的JSON文本編碼問題解決辦法

    MySQL錯誤代碼3140:無效的JSON文本編碼問題解決辦法

    下面這篇文章主要給大家介紹了關(guān)于MySQL錯誤代碼3140:無效的JSON文本編碼問題的解決辦法,文中通過代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用mysql具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-03-03

最新評論