3.1 order by
當(dāng)使用SELECT語(yǔ)句查詢表中的數(shù)據(jù)時(shí),結(jié)果集不按任何順序進(jìn)行排序。要對(duì)結(jié)果集進(jìn)行排序,請(qǐng)使用ORDER BY
子句。
ORDER BY
子句允許:
對(duì)單個(gè)列或多個(gè)列排序結(jié)果集。
按升序或降序?qū)Σ煌械慕Y(jié)果集進(jìn)行排序。
下面說(shuō)明了ORDER BY
子句的語(yǔ)法:
SELECT column1, column2,...
FROM tbl
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC],...
SQL
ASC
表示升序,DESC
表示降序。默認(rèn)情況下,如果不明確指定ASC
或DESC
,ORDER BY
子句會(huì)按照升序?qū)Y(jié)果集進(jìn)行排序。
下面我們來(lái)學(xué)習(xí)和練習(xí)一些使用ORDER BY子句的例子。
請(qǐng)參見(jiàn)示例數(shù)據(jù)庫(kù)(yiibaidb)中的customers
表,customers
表的結(jié)構(gòu)如下所示 -
以下查詢從customers
表中查詢聯(lián)系人,并按contactLastname
升序?qū)β?lián)系人進(jìn)行排序。
SELECT contactLastname, contactFirstname
FROM customers
ORDER BY contactLastname;
SQL
執(zhí)行上面查詢,得到以下結(jié)果 -
mysql> SELECT contactLastname, contactFirstnameFROM customersORDER BY contactLastname; ----------------- ------------------ | contactLastname | contactFirstname | ----------------- ------------------ | Accorti | Paolo || Altagar,G M | Raanan || Andersen | Mel || Anton | Carmen || Ashworth | Rachel || Barajas | Miguel || Benitez | Violeta || Bennett | Helen || Berglund | Christina || Bergulfsen | Jonas || Bertrand | Marie |... ....| Young | Julie || Young | Mary || Young | Dorothy | ----------------- ------------------ 122 rows in set
Shell
如果要按姓氏降序?qū)β?lián)系人進(jìn)行排序,請(qǐng)?jiān)?code>ORDER BY子句中的contactLastname
列后面指定DESC
,如下查詢:
SELECT contactLastname, contactFirstname
FROM customers
ORDER BY contactLastname DESC;
SQL
執(zhí)行上面查詢,得到以下結(jié)果 -
mysql> SELECT contactLastname, contactFirstnameFROM customersORDER BY contactLastname DESC; ----------------- ------------------ | contactLastname | contactFirstname | ----------------- ------------------ | Young | Jeff || Young | Julie || Young | Mary |... ...| Anton | Carmen || Andersen | Mel || Altagar,G M | Raanan || Accorti | Paolo | ----------------- ------------------ 122 rows in set
Shell
如果要按姓氏按降序和名字按升序排序聯(lián)系人,請(qǐng)?jiān)谙鄳?yīng)列中分別指定DESC
和ASC
,如下所示:
SELECT contactLastname, contactFirstname
FROM customers
ORDER BY contactLastname DESC, contactFirstname ASC;
SQL
執(zhí)行上面查詢,得到以下結(jié)果 -
mysql> SELECT contactLastname, contactFirstnameFROM customersORDER BY contactLastname DESC, contactFirstname ASC; ----------------- ------------------ | contactLastname | contactFirstname | ----------------- ------------------ | Young | Dorothy || Young | Jeff || Young | Julie || Young | Mary || Yoshido | Juri || Walker | Brydey || Victorino | Wendy || Urs | Braun || Tseng | Jerry |... ...| Brown | Julie || Brown | William || Bertrand | Marie || Bergulfsen | Jonas || Berglund | Christina || Bennett | Helen || Benitez | Violeta || Barajas | Miguel || Ashworth | Rachel || Anton | Carmen || Andersen | Mel || Altagar,G M | Raanan || Accorti | Paolo | ----------------- ------------------ 122 rows in set
Shell
在上面的查詢中,ORDER BY
子句首先按照contactLastname
列降序?qū)Y(jié)果集進(jìn)行排序,然后按照contactFirstname
列升序?qū)ε判蚪Y(jié)果集進(jìn)行排序,以生成最終結(jié)果集。
MySQL ORDER BY按表達(dá)式排序示例
ORDER BY
子句還允許您根據(jù)表達(dá)式對(duì)結(jié)果集進(jìn)行排序。請(qǐng)參閱以下orderdetails
表結(jié)構(gòu) -
以下查詢從orderdetails
表中選擇訂單行記錄項(xiàng)目。它計(jì)算每個(gè)訂單項(xiàng)的小計(jì),并根據(jù)訂單編號(hào),訂單行號(hào)(orderLineNumber
)和小計(jì)(quantityOrdered * priceEach
)對(duì)結(jié)果集進(jìn)行排序。
SELECT ordernumber, orderlinenumber, quantityOrdered * priceEach
FROM orderdetails
ORDER BY ordernumber, orderLineNumber, quantityOrdered * priceEach;
SQL
執(zhí)行上面語(yǔ)句,總共有 2996
行結(jié)果集,以下是部分結(jié)果集片斷 -
為了使查詢更易于閱讀,可以按列別名進(jìn)行排序,方法如下:
SELECT ordernumber, orderlinenumber, quantityOrdered * priceEach AS subtotal
FROM orderdetails
ORDER BY ordernumber, orderLineNumber, subtotal;
SQL
執(zhí)行上面語(yǔ)句,總共有 2996
行結(jié)果集,以下是部分結(jié)果集片斷 -
上面表達(dá)式中,使用subtotal
作為表達(dá)式quantityOrdered * priceEach
的列別名,并根據(jù)小計(jì)別名(subtotal
)對(duì)結(jié)果集進(jìn)行排序。
ORDER BY
子句允許使用FIELD()
函數(shù)為列中的值定義自己的自定義排序順序。
看看下面 orders
表的結(jié)構(gòu)如下所示 -
例如,如果要按以下順序基于以下?tīng)顟B(tài)的值對(duì)訂單進(jìn)行排序:
In Process
On Hold
Cancelled
Resolved
Disputed
Shipped
可以使用FIELD()
函數(shù)將這些值映射到數(shù)值列表,并使用數(shù)字進(jìn)行排序; 請(qǐng)參閱以下查詢:
SELECT orderNumber, status
FROM orders
ORDER BY FIELD(status, 'In Process', 'On Hold', 'Cancelled', 'Resolved', 'Disputed', 'Shipped');
SQL
執(zhí)行上面查詢語(yǔ)句,得到以下結(jié)果 -
mysql> SELECT orderNumber, statusFROM ordersORDER BY FIELD(status, 'In Process', 'On Hold', 'Cancelled', 'Resolved', 'Disputed', 'Shipped'); ------------- ------------ | orderNumber | status | ------------- ------------ | 10420 | In Process || 10421 | In Process || 10422 | In Process || 10423 | In Process || 10424 | In Process || 10425 | In Process || 10334 | On Hold || 10401 | On Hold || 10407 | On Hold || 10414 | On Hold || 10167 | Cancelled || 10179 | Cancelled || 10248 | Cancelled || 10253 | Cancelled || 10260 | Cancelled || 10262 | Cancelled || 10164 | Resolved || 10327 | Resolved |... ...| 10413 | Shipped || 10416 | Shipped || 10418 | Shipped || 10419 | Shipped | ------------- ------------ 326 rows in set
3 MySQL GROUP BY與聚合函數(shù)
可使用聚合函數(shù)來(lái)執(zhí)行一組行的計(jì)算并返回單個(gè)值。 GROUP BY
子句通常與聚合函數(shù)一起使用以執(zhí)行計(jì)算每個(gè)分組并返回單個(gè)值。
例如,如果想知道每個(gè)狀態(tài)中的訂單數(shù),可以使用COUNT
函數(shù)與GROUP BY
子句查詢語(yǔ)句,如下所示:
SELECT status, COUNT(*) AS total_number
FROM orders
GROUP BY status;
SQL
執(zhí)行上面查詢語(yǔ)句,得到以下結(jié)果 -
要按狀態(tài)獲取所有訂單的總金額,可以使用orderdetails
表連接orders
表,并使用SUM
函數(shù)計(jì)算總金額。請(qǐng)參閱以下查詢:
SELECT status, SUM(quantityOrdered * priceEach) AS amount
FROM orders
INNER JOIN orderdetails USING (orderNumber)
GROUP BY status;
SQL
執(zhí)行上面查詢,得到以下結(jié)果 -
類似地,以下查詢返回訂單號(hào)和每個(gè)訂單的總金額。
SELECT orderNumber, SUM(quantityOrdered * priceEach) AS total
FROM orderdetails
GROUP BY orderNumber;
SQL
執(zhí)行上面查詢,得到以下結(jié)果 -
2.3 MySQL GROUP BY用表達(dá)式示例
除了列之外,可以按表達(dá)式對(duì)行進(jìn)行分組。以下查詢獲取每年的總銷售額。
SELECT YEAR(orderDate) AS year, SUM(quantityOrdered * priceEach) AS total
FROM orders
INNER JOIN orderdetails USING (orderNumber)
WHERE status = 'Shipped'
GROUP BY YEAR(orderDate);
SQL
執(zhí)行上面查詢,得到以下結(jié)果 -
在這個(gè)例子中,我們使用YEAR函數(shù)從訂單日期(orderDate
)中提取年份數(shù)據(jù)。只包括已發(fā)貨(Shipped
)狀態(tài)的訂單。 請(qǐng)注意,SELECT
子句中出現(xiàn)的表達(dá)式必須與GROUP BY
子句中的相同。
可使用HAVING子句過(guò)濾GROUP BY
子句返回的分組。以下查詢使用HAVING
子句來(lái)選擇2013
年以后的年銷售總額。
SELECT YEAR(orderDate) AS year, SUM(quantityOrdered * priceEach) AS total
FROM orders
INNER JOIN orderdetails USING (orderNumber)
WHERE status = 'Shipped'GROUP BY year
HAVING year > 2013;
SQL
執(zhí)行上面查詢,得到以下結(jié)果 -
3.2 order by 子句與自然語(yǔ)言排序
在本教程中,您將使用ORDER BY
子句了解MySQL中的各種自然排序技術(shù)。
下面讓我們使用一個(gè)示例數(shù)據(jù)來(lái)開(kāi)始學(xué)習(xí)自然排序技術(shù)。
假設(shè)我們有一個(gè)items
的表,其中包含兩列:id
和item_no
。使用以下CREATE TABLE語(yǔ)句創(chuàng)建items
表,如下:
CREATE TABLE IF NOT EXISTS items ( id INT AUTO_INCREMENT PRIMARY KEY, item_no VARCHAR(255) NOT NULL);
SQL
我們使用INSERT語(yǔ)句將一些數(shù)據(jù)插入到items
表中:
INSERT INTO items(item_no)
VALUES ('1'), ('1C'), ('10Z'), ('2A'), ('2'), ('3C'), ('20D');
SQL
當(dāng)我們查詢選擇數(shù)據(jù)并按item_no
排序時(shí),得到以下結(jié)果:
這不是我們的預(yù)期的結(jié)果,我們想要看到的結(jié)果如下:
這被稱為自然排序。不幸的是,MySQL不提供任何內(nèi)置的自然排序語(yǔ)法或函數(shù)。 ORDER BY子句以線性方式排序字符串,即從第一個(gè)字符開(kāi)始的每個(gè)字符一次。
為了克服這個(gè)問(wèn)題,首先我們將item_no
列分成兩列:prefix
和 suffix
。 prefix
列存儲(chǔ)item_no
的數(shù)字部分,suffix
列存儲(chǔ)字母部分。然后根據(jù)這些列對(duì)數(shù)據(jù)進(jìn)行排序,如下所示:
SELECT CONCAT(prefix, suffix)
FROM items
ORDER BY prefix , suffix;
SQL
查詢首先對(duì)數(shù)據(jù)進(jìn)行數(shù)字排序,并按字母順序?qū)?shù)據(jù)進(jìn)行排序。我們就得到預(yù)期的結(jié)果。
這個(gè)解決方案的缺點(diǎn)是必須在插入或更新之前將item_no
值分成兩部分。 此外,當(dāng)查詢數(shù)據(jù)時(shí),必須將這兩列組合成一列。
如果item_no
數(shù)據(jù)格式相當(dāng)標(biāo)準(zhǔn),則可以使用以下查詢執(zhí)行自然排序,而無(wú)需更改表的結(jié)構(gòu)。
SELECT item_no
FROM items
ORDER BY CAST(item_no AS UNSIGNED) , item_no;
SQL
執(zhí)行上面查詢語(yǔ)句,得到以下結(jié)果 -
SELECT item_noFROM itemsORDER BY CAST(item_no AS UNSIGNED) , item_no;
Shell
在這個(gè)查詢中,首先使用類型轉(zhuǎn)換將item_no
數(shù)據(jù)轉(zhuǎn)換為無(wú)符號(hào)整數(shù)。 其次,使用ORDER BY
子句對(duì)數(shù)字進(jìn)行數(shù)字排序,然后按字母順序排列。
下面來(lái)看看經(jīng)常要處理的另一個(gè)常見(jiàn)的數(shù)據(jù)。
TRUNCATE TABLE items;INSERT INTO items(item_no)
VALUES('A-1'), ('A-2'), ('A-3'), ('A-4'), ('A-5'), ('A-10'), ('A-11'), ('A-20'), ('A-30');
SQL
排序后的預(yù)期結(jié)果如下:
為了得到上面這個(gè)結(jié)果,可以使用LENGTH函數(shù)。 請(qǐng)注意,LENGTH函數(shù)返回字符串的長(zhǎng)度。 這個(gè)做法是首先對(duì)item_no
數(shù)據(jù)進(jìn)行排序,然后按列值排序,如以下查詢:
SELECT item_no
FROM items
ORDER BY LENGTH(item_no) , item_no;
SQL
執(zhí)行上面查詢,得到以下結(jié)果 -
mysql> SELECT item_noFROM itemsORDER BY LENGTH(item_no) , item_no; --------- | item_no | --------- | A-1 || A-2 || A-3 || A-4 || A-5 || A-10 || A-11 || A-20 || A-30 | --------- 9 rows in set
Shell
如下所看到數(shù)據(jù)就是自然排序的。
但是,如果所有上述解決方案都不適合。 則需要在應(yīng)用程序?qū)訄?zhí)行自然排序。 一些語(yǔ)言支持自然排序功能,例如,PHP提供了使用自然排序算法對(duì)數(shù)組進(jìn)行排序的natsort()函數(shù)。
3.3 Having 子句
在SELECT語(yǔ)句中使用HAVING
子句來(lái)指定一組行或聚合的過(guò)濾條件。
HAVING
子句通常與GROUP BY子句一起使用,以根據(jù)指定的條件過(guò)濾分組。如果省略GROUP BY
子句,則HAVING
子句的行為與WHERE
子句類似。
請(qǐng)注意,
HAVING
子句將過(guò)濾條件應(yīng)用于每組分行,而WHERE
子句將過(guò)濾條件應(yīng)用于每個(gè)單獨(dú)的行。
讓我們舉一些使用HAVING
子句的例子來(lái)看看它是如何工作。 我們將使用示例數(shù)據(jù)庫(kù)(yiibaidb)中的orderdetails
表進(jìn)行演示。
GROUP BY
子句來(lái)獲取訂單號(hào),查看每個(gè)訂單銷售的商品數(shù)量和每個(gè)銷售總額:SELECT ordernumber, SUM(quantityOrdered) AS itemsCount, SUM(priceeach*quantityOrdered) AS total
FROM orderdetails
GROUP BY ordernumber;
SQL
執(zhí)行上面查詢語(yǔ)句,得到以下結(jié)果(部分) -
現(xiàn)在,可以通過(guò)使用HAVING
子句查詢(過(guò)濾)哪些訂單的總銷售額大于55000
,如下所示:
SELECT ordernumber, SUM(quantityOrdered) AS itemsCount, SUM(priceeach*quantityOrdered) AS totalFROM orderdetailsGROUP BY ordernumberHAVING total > 55000;
SQL
執(zhí)行上面查詢語(yǔ)句,得到以下結(jié)果 -
可以使用邏輯運(yùn)算符(如OR
和AND
)在HAVING
子句中構(gòu)造復(fù)雜過(guò)濾條件。 假設(shè)您想查找哪些訂單的總銷售額大于50000
,并且包含超過(guò)600
個(gè)項(xiàng)目,則可以使用以下查詢:
SELECT ordernumber, SUM(quantityOrdered) AS itemsCount, SUM(priceeach*quantityOrdered) AS total
FROM orderdetails
GROUP BY ordernumber
HAVING total > 50000 AND itemsCount > 600;
SQL
執(zhí)行上面查詢語(yǔ)句,得到以下結(jié)果 -
假設(shè)您想查找所有已發(fā)貨(status='Shiped'
)的訂單和總銷售額大于55000
的訂單,可以使用INNER JOIN子句將orders
表與orderdetails
表一起使用,并在status
列和總金額(total
)列上應(yīng)用條件,如以下查詢所示:
執(zhí)行上面查詢,得到以下結(jié)果 -
HAVING
子句僅在使用GROUP BY
子句生成高級(jí)報(bào)告的輸出時(shí)才有用。 例如,您可以使用HAVING
子句來(lái)回答統(tǒng)計(jì)問(wèn)題,例如在本月,本季度或今年總銷售額超過(guò)10000
的訂單。
聯(lián)系客服