概述
資料庫中的資料直接呈現出來一般不是我們想要的,所以我們上兩節演示瞭如何對資料進行過濾的方法。除了對資料進行過濾,
我們可能還需要對資料進行排序,比如想從列表中瞭解消費最高的項,就可能需要對金額欄位做降序排序,想看年齡從小到大的分佈情況,就可能需要對user表的age欄位進行升序排序。
也可能需要對資料進行限制,比如我們需要對付款的1~10,11~20,21~30 名的使用者分別贈予不同的禮品,這時候對資料的限制就很有用了。
備註:下面指令碼中[]包含的表示可選,| 分隔符表示可選其一。
資料排序 order by
語法格式如下:
1、需要排序的欄位跟在order by
之後;
2、asc 和 desc表示排序的規則,asc:升序,desc:降序,預設為升序 asc;
3、排序可以指定多次欄位,多欄位排序之間用逗號隔開。
4、多欄位排序中,越靠前優先順序越高,下面中cname1優先排序,當cname1等值的時候,cname2開始排序,直至所有欄位都排序完。
1 select cname from tname order by cname1 [asc|desc],cname2 [asc|desc]...;
單個欄位排序
舉個例子,在銷售額中通按照交易的訂單進行金額額度降序的方式顯示:
1 mysql> select * from t_order; 2 +---------+---------+---------+-------+ 3 | orderid | account | amount | goods | 4 +---------+---------+---------+-------+ 5 | 8 | brand | 52.2 | 2 | 6 | 9 | hen | 1752.02 | 7 | 7 | 10 | helyn | 88.5 | 4 | 8 | 11 | sol | 1007.9 | 11 | 9 | 12 | diny | 12 | 1 | 10 | 13 | weng | 52.2 | 5 | 11 | 14 | sally | 99.71 | 9 | 12 +---------+---------+---------+-------+ 13 7 rows in set 14 15 mysql> select * from t_order order by amount desc; 16 +---------+---------+---------+-------+ 17 | orderid | account | amount | goods | 18 +---------+---------+---------+-------+ 19 | 9 | hen | 1752.02 | 7 | 20 | 11 | sol | 1007.9 | 11 | 21 | 14 | sally | 99.71 | 9 | 22 | 10 | helyn | 88.5 | 4 | 23 | 8 | brand | 52.2 | 2 | 24 | 13 | weng | 52.2 | 5 | 25 | 12 | diny | 12 | 1 | 26 +---------+---------+---------+-------+ 27 7 rows in set
多個欄位排序
多個欄位排序用逗號隔開,優先順序從左到右逐次遞減,如下圖,如果金額一致,則按照購買商品數量從多到少排序:
1 mysql> select * from t_order order by amount desc,goods desc; 2 +---------+---------+---------+-------+ 3 | orderid | account | amount | goods | 4 +---------+---------+---------+-------+ 5 | 9 | hen | 1752.02 | 7 | 6 | 11 | sol | 1007.9 | 11 | 7 | 14 | sally | 99.71 | 9 | 8 | 10 | helyn | 88.5 | 4 | 9 | 13 | weng | 52.2 | 5 | 10 | 8 | brand | 52.2 | 2 | 11 | 12 | diny | 12 | 1 | 12 +---------+---------+---------+-------+ 13 7 rows in set
按alias排序
按照別名排序或者做條件查詢的目的都是為了簡化程式碼,方便使用,別名可以是英文,也可以是中文:
1 mysql> select account as ac,amount as am,goods as gd from t_order order by am,gd desc; 2 3 +-------+---------+----+ 4 | ac | am | gd | 5 +-------+---------+----+ 6 | diny | 12 | 1 | 7 | weng | 52.2 | 5 | 8 | brand | 52.2 | 2 | 9 | helyn | 88.5 | 4 | 10 | sally | 99.71 | 9 | 11 | sol | 1007.9 | 11 | 12 | hen | 1752.02 | 7 | 13 +-------+---------+----+ 14 7 rows in set
欄位排序中使用函式
下面使用了abs取絕對值函式,所以在 am欄位降序排序中,-99.99 排在 99.71之上。
1 mysql> select * from t_order; 2 +---------+---------+---------+-------+ 3 | orderid | account | amount | goods | 4 +---------+---------+---------+-------+ 5 | 8 | brand | 52.2 | 2 | 6 | 9 | hen | 1752.02 | 7 | 7 | 10 | helyn | 88.5 | 4 | 8 | 11 | sol | 1007.9 | 11 | 9 | 12 | diny | 12 | 1 | 10 | 13 | weng | 52.2 | 5 | 11 | 14 | sally | 99.71 | 9 | 12 | 15 | brand1 | -99.99 | 5 | 13 +---------+---------+---------+-------+ 14 8 rows in set 15 16 mysql> select account as ac,amount as am,goods as gd from t_order order by abs(am) desc; 17 18 +--------+---------+----+ 19 | ac | am | gd | 20 +--------+---------+----+ 21 | hen | 1752.02 | 7 | 22 | sol | 1007.9 | 11 | 23 | brand1 | -99.99 | 5 | 24 | sally | 99.71 | 9 | 25 | helyn | 88.5 | 4 | 26 | brand | 52.2 | 2 | 27 | weng | 52.2 | 5 | 28 | diny | 12 | 1 | 29 +--------+---------+----+ 30 8 rows in set
與Where條件結合使用
order 在 where 條件之後,根據where已經過濾好的資料再進行排序。下面是過濾出購買金額>80 且 購買數量>5的資料,並且按照價格降序排序。
1 mysql> select * from t_order; 2 +---------+---------+---------+-------+ 3 | orderid | account | amount | goods | 4 +---------+---------+---------+-------+ 5 | 8 | brand | 52.2 | 2 | 6 | 9 | hen | 1752.02 | 7 | 7 | 10 | helyn | 88.5 | 4 | 8 | 11 | sol | 1007.9 | 11 | 9 | 12 | diny | 12 | 1 | 10 | 13 | weng | 52.2 | 5 | 11 | 14 | sally | 99.71 | 9 | 12 | 15 | brand1 | -99.99 | 5 | 13 +---------+---------+---------+-------+ 14 8 rows in set 15 16 mysql> select * from t_order where amount>80 and goods>5 order by amount desc; 17 +---------+---------+---------+-------+ 18 | orderid | account | amount | goods | 19 +---------+---------+---------+-------+ 20 | 9 | hen | 1752.02 | 7 | 21 | 11 | sol | 1007.9 | 11 | 22 | 14 | sally | 99.71 | 9 | 23 +---------+---------+---------+-------+
資料limit
很多時候我們過濾出符合要求的資料之後,還需要得到這些資料中的某一個具體區間,比如對付款超過1000的使用者的第1~10,11~20,21~30 名分別贈予不同的禮品,這時候就要使用limit操作了。
limit用來限制select查詢返回的資料,常用於資料排行或者分頁等情況。
語法格式如下:
1 select cname from tname limit [offset,] count;
1、offset表示偏移量,就是指跳過的行數,可以省略不寫,預設為0,表示跳過0行,如 limit 8 等同於 limit 0,8。
2、count:跳過偏移量offset之後開始取的資料行數,有count行。
3、limit中offset和count的值不能用表示式。
獲取前n條記錄
如下圖,limit n 和 limit 0,n 是一致的:
1 mysql> select * from t_order; 2 +---------+---------+---------+-------+ 3 | orderid | account | amount | goods | 4 +---------+---------+---------+-------+ 5 | 8 | brand | 52.2 | 2 | 6 | 9 | hen | 1752.02 | 7 | 7 | 10 | helyn | 88.5 | 4 | 8 | 11 | sol | 1007.9 | 11 | 9 | 12 | diny | 12 | 1 | 10 | 13 | weng | 52.2 | 5 | 11 | 14 | sally | 99.71 | 9 | 12 | 15 | brand1 | -99.99 | 5 | 13 +---------+---------+---------+-------+ 14 8 rows in set 15 16 mysql> select * from t_order limit 2 17 ; 18 +---------+---------+---------+-------+ 19 | orderid | account | amount | goods | 20 +---------+---------+---------+-------+ 21 | 8 | brand | 52.2 | 2 | 22 | 9 | hen | 1752.02 | 7 | 23 +---------+---------+---------+-------+ 24 2 rows in set 25 26 mysql> select * from t_order limit 0,2; 27 +---------+---------+---------+-------+ 28 | orderid | account | amount | goods | 29 +---------+---------+---------+-------+ 30 | 8 | brand | 52.2 | 2 | 31 | 9 | hen | 1752.02 | 7 | 32 +---------+---------+---------+-------+ 33 2 rows in set
limit限制單條記錄
這邊我們獲取支付金額中最大和最小的的一條記錄。可以先使用 order 條件進行排序,然後limit 第1條記錄即可:
1 1 mysql> select * from t_order; 2 2 +---------+---------+---------+-------+ 3 3 | orderid | account | amount | goods | 4 4 +---------+---------+---------+-------+ 5 5 | 8 | brand | 52.2 | 2 | 6 6 | 9 | hen | 1752.02 | 7 | 7 7 | 10 | helyn | 88.5 | 4 | 8 8 | 11 | sol | 1007.9 | 11 | 9 9 | 12 | diny | 12 | 1 | 10 10 | 13 | weng | 52.2 | 5 | 11 11 | 14 | sally | 99.71 | 9 | 12 12 | 15 | brand1 | -99.99 | 5 | 13 13 +---------+---------+---------+-------+ 14 14 8 rows in set 15 15 16 16 mysql> select * from t_order where amount>0 order by amount desc limit 1; 17 17 +---------+---------+---------+-------+ 18 18 | orderid | account | amount | goods | 19 19 +---------+---------+---------+-------+ 20 20 | 9 | hen | 1752.02 | 7 | 21 21 +---------+---------+---------+-------+ 22 22 1 row in set 23 23 24 24 mysql> select * from t_order where amount>0 order by amount asc limit 1; 25 25 +---------+---------+--------+-------+ 26 26 | orderid | account | amount | goods | 27 27 +---------+---------+--------+-------+ 28 28 | 12 | diny | 12 | 1 | 29 29 +---------+---------+--------+-------+ 30 30 1 row in set 31
獲取(m,n)區間記錄
即跳過m條,獲取n條,示例如下,我們跳過兩條,從第三條開始,連取四條的操作:
1 mysql> select * from t_order order by amount; 2 +---------+---------+---------+-------+ 3 | orderid | account | amount | goods | 4 +---------+---------+---------+-------+ 5 | 15 | brand1 | -99.99 | 5 | 6 | 12 | diny | 12 | 1 | 7 | 8 | brand | 52.2 | 2 | 8 | 13 | weng | 52.2 | 5 | 9 | 10 | helyn | 88.5 | 4 | 10 | 14 | sally | 99.71 | 9 | 11 | 11 | sol | 1007.9 | 11 | 12 | 9 | hen | 1752.02 | 7 | 13 +---------+---------+---------+-------+ 14 8 rows in set 15 16 mysql> select * from t_order order by amount limit 2,4; 17 +---------+---------+--------+-------+ 18 | orderid | account | amount | goods | 19 +---------+---------+--------+-------+ 20 | 8 | brand | 52.2 | 2 | 21 | 13 | weng | 52.2 | 5 | 22 | 10 | helyn | 88.5 | 4 | 23 | 14 | sally | 99.71 | 9 | 24 +---------+---------+--------+-------+ 25 4 rows in set
分頁的做法與這個類似,我們程式業務上看到的分頁一般有 pageIndex,pageSize等引數,我們通常的做法是 limit pageIndex*pageSize,pageSize。
這邊假設有31條資料,每頁數量pageSize=10,頁面索引pageIndex預設0,則第一頁就是 limit 0,10,第二頁 limit10,10,第三頁 limit 20,10,第四頁 limit 30,10。
注意點:
1、limit 後面不能使用表示式,只能使用明確的數值,否則會爆出異常,比如 limit 0*10,10,是不對的,這個上面提過了。
2、limit後續的數值只能是正整數和0,也就是說,不能是負數,否則同樣會報錯。
3、排序欄位的值相同情況下,排序後分頁會出現混亂重複的情況。
第3點詳細說明下:假如根據age排序,但是有多個age都是20歲的同學,這時候我們3條記錄一頁,就會出現分頁混亂資料重複。因為年齡相同的人有多個,這是幾個人的排序在每次查詢的時候會有不確定性。
舉個例子,下面的分頁,混亂了:
1 mysql> select * from user3; 2 +----+------+-------+ 3 | id | age | name | 4 +----+------+-------+ 5 | 1 | 20 | brand | 6 | 2 | 22 | sol | 7 | 3 | 20 | helen | 8 | 4 | 19.5 | diny | 9 | 6 | 19 | a | 10 | 7 | 20 | b | 11 | 8 | 20 | c | 12 | 9 | 20 | d | 13 | 10 | 20 | e | 14 | 11 | 23 | f | 15 +----+------+-------+ 16 10 rows in set 17 18 mysql> select * from user3 order by age limit 0,3; 19 +----+------+-------+ 20 | id | age | name | 21 +----+------+-------+ 22 | 6 | 19 | a | 23 | 4 | 19.5 | diny | 24 | 3 | 20 | helen | 25 +----+------+-------+ 26 3 rows in set 27 28 mysql> select * from user3 order by age limit 3,3; 29 30 +----+-----+-------+ 31 | id | age | name | 32 +----+-----+-------+ 33 | 3 | 20 | helen | 34 | 7 | 20 | b | 35 | 8 | 20 | c | 36 +----+-----+-------+ 37 3 rows in set 38 39 mysql> select * from user3 order by age limit 6,3; 40 41 +----+-----+-------+ 42 | id | age | name | 43 +----+-----+-------+ 44 | 7 | 20 | b | 45 | 3 | 20 | helen | 46 | 2 | 22 | sol | 47 +----+-----+-------+ 48 3 rows in set
我們的做法是使用重複值欄位做排序的時候再加個唯一依據(一般可以設主鍵),就不會混亂了。
如下示例,正常了:
1 mysql> select * from user3; 2 +----+------+-------+ 3 | id | age | name | 4 +----+------+-------+ 5 | 1 | 20 | brand | 6 | 2 | 22 | sol | 7 | 3 | 20 | helen | 8 | 4 | 19.5 | diny | 9 | 6 | 19 | a | 10 | 7 | 20 | b | 11 | 8 | 20 | c | 12 | 9 | 20 | d | 13 | 10 | 20 | e | 14 | 11 | 23 | f | 15 +----+------+-------+ 16 10 rows in set 17 18 mysql> select * from user3 order by age,id limit 0,3; 19 20 +----+------+-------+ 21 | id | age | name | 22 +----+------+-------+ 23 | 6 | 19 | a | 24 | 4 | 19.5 | diny | 25 | 1 | 20 | brand | 26 +----+------+-------+ 27 3 rows in set 28 29 mysql> select * from user3 order by age,id limit 3,3; 30 31 +----+-----+-------+ 32 | id | age | name | 33 +----+-----+-------+ 34 | 3 | 20 | helen | 35 | 7 | 20 | b | 36 | 8 | 20 | c | 37 +----+-----+-------+ 38 3 rows in set 39 40 mysql> select * from user3 order by age,id limit 6,3; 41 42 +----+-----+------+ 43 | id | age | name | 44 +----+-----+------+ 45 | 9 | 20 | d | 46 | 10 | 20 | e | 47 | 2 | 22 | sol | 48 +----+-----+------+ 49 3 rows in set
上述總結
1、order by cname [asc|desc] 用於對查詢結果排序,asc為升序,desc為降序,可以省略,省略情況下預設為asc。
2、limit用來限制查詢結果返回的行數,包含2個引數(offset,count),offset:表示跳過多少行,count:表示跳過offset行之後取的行數。limit中offset可以省略,預設值為0;limit中offset 和 count都必須大於等於0;limit中offset和count的值不能用表示式。
3、分頁排序時,排序欄位不要有重複值,重複值情況下可能會導致分頁結果混亂,建議在後面加一個主鍵排序。