溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Mysql排序和分頁(order by&limit)及存在的坑

發(fā)布時間:2020-10-16 15:52:15 來源:腳本之家 閱讀:182 作者:易兮科技 欄目:開發(fā)技術

排序查詢(order by)

電商中:我們想查看今天所有成交的訂單,按照交易額從高到低排序,此時我們可以使用數(shù)據(jù)庫中的排序功能來完成。

排序語法:

select 字段名 from 表名 order by 字段1 [asc|desc],字段2 [asc|desc];
  • 需要排序的字段跟在order by之后;
  • asc|desc表示排序的規(guī)則,asc:升序,desc:降序,默認為asc;
  • 支持多個字段進行排序,多字段排序之間用逗號隔開。

單字段排序

mysql> create table test2(a int,b varchar(10));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into test2 values (10,'jack'),(8,'tom'),(5,'ready'),(100,'javacode');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from test2;
+------+----------+
| a  | b    |
+------+----------+
|  10 | jack   |
|  8 | tom   |
|  5 | ready  |
| 100 | javacode |
+------+----------+
4 rows in set (0.00 sec)
mysql> select * from test2 order by a asc;
+------+----------+
| a  | b    |
+------+----------+
|  5 | ready  |
|  8 | tom   |
|  10 | jack   |
| 100 | javacode |
+------+----------+
4 rows in set (0.00 sec)
mysql> select * from test2 order by a desc;
+------+----------+
| a  | b    |
+------+----------+
| 100 | javacode |
|  10 | jack   |
|  8 | tom   |
|  5 | ready  |
+------+----------+
4 rows in set (0.00 sec)
mysql> select * from test2 order by a;
+------+----------+
| a  | b    |
+------+----------+
|  5 | ready  |
|  8 | tom   |
|  10 | jack   |
| 100 | javacode |
+------+----------+
4 rows in set (0.00 sec)

多字段排序

比如學生表,先按學生年齡降序,年齡相同時,再按學號升序,如下:

mysql> create table stu(id int not null comment '學號' primary key,age tinyint not null comment '年齡',name varchar(16) comment '姓名');
Query OK, 0 rows affected (0.01 sec)
mysql> insert into stu (id,age,name) values (1001,18,'路人甲Java'),(1005,20,'劉德華'),(1003,18,'張學友'),(1004,20,'張國榮'),(1010,19,'梁朝偉');
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from stu;
+------+-----+---------------+
| id  | age | name     |
+------+-----+---------------+
| 1001 | 18 | 路人甲Java  |
| 1003 | 18 | 張學友    |
| 1004 | 20 | 張國榮    |
| 1005 | 20 | 劉德華    |
| 1010 | 19 | 梁朝偉    |
+------+-----+---------------+
5 rows in set (0.00 sec)
mysql> select * from stu order by age desc,id asc;
+------+-----+---------------+
| id  | age | name     |
+------+-----+---------------+
| 1004 | 20 | 張國榮    |
| 1005 | 20 | 劉德華    |
| 1010 | 19 | 梁朝偉    |
| 1001 | 18 | 路人甲Java  |
| 1003 | 18 | 張學友    |
+------+-----+---------------+
5 rows in set (0.00 sec)

按別名排序

mysql> select * from stu;
+------+-----+---------------+
| id  | age | name     |
+------+-----+---------------+
| 1001 | 18 | 路人甲Java  |
| 1003 | 18 | 張學友    |
| 1004 | 20 | 張國榮    |
| 1005 | 20 | 劉德華    |
| 1010 | 19 | 梁朝偉    |
+------+-----+---------------+
5 rows in set (0.00 sec)
mysql> select age '年齡',id as '學號' from stu order by 年齡 asc,學號 desc;
+--------+--------+
| 年齡  | 學號  |
+--------+--------+
|   18 |  1003 |
|   18 |  1001 |
|   19 |  1010 |
|   20 |  1005 |
|   20 |  1004 |
+--------+--------+

按函數(shù)排序

有學生表(id:編號,birth:出生日期,name:姓名),如下:

mysql> drop table if exists student;
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE student (
  ->  id int(11) NOT NULL COMMENT '學號',
  ->  birth date NOT NULL COMMENT '出生日期',
  ->  name varchar(16) DEFAULT NULL COMMENT '姓名',
  ->  PRIMARY KEY (id)
  -> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into student (id,birth,name) values (1001,'1990-10-10','路人甲Java'),(1005,'1960-03-01','劉德華'),(1003,'1960-08-16','張學友'),(1004,'1968-07-01','張國榮'),(1010,'1962-05-16','梁朝偉');
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql>
mysql> SELECT * FROM student;
+------+------------+---------------+
| id  | birth   | name     |
+------+------------+---------------+
| 1001 | 1990-10-10 | 路人甲Java  |
| 1003 | 1960-08-16 | 張學友    |
| 1004 | 1968-07-01 | 張國榮    |
| 1005 | 1960-03-01 | 劉德華    |
| 1010 | 1962-05-16 | 梁朝偉    |
+------+------------+---------------+
5 rows in set (0.00 sec)

需求:按照出生年份升序、編號升序,查詢出編號、出生日期、出生年份、姓名,2種寫法如下:

mysql> SELECT id 編號,birth 出生日期,year(birth) 出生年份,name 姓名 from student ORDER BY year(birth) asc,id asc;
+--------+--------------+--------------+---------------+
| 編號  | 出生日期   | 出生年份   | 姓名     |
+--------+--------------+--------------+---------------+
|  1003 | 1960-08-16  |     1960 | 張學友    |
|  1005 | 1960-03-01  |     1960 | 劉德華    |
|  1010 | 1962-05-16  |     1962 | 梁朝偉    |
|  1004 | 1968-07-01  |     1968 | 張國榮    |
|  1001 | 1990-10-10  |     1990 | 路人甲Java  |
+--------+--------------+--------------+---------------+
5 rows in set (0.00 sec)
mysql> SELECT id 編號,birth 出生日期,year(birth) 出生年份,name 姓名 from student ORDER BY 出生年份 asc,id asc;
+--------+--------------+--------------+---------------+
| 編號  | 出生日期   | 出生年份   | 姓名     |
+--------+--------------+--------------+---------------+
|  1003 | 1960-08-16  |     1960 | 張學友    |
|  1005 | 1960-03-01  |     1960 | 劉德華    |
|  1010 | 1962-05-16  |     1962 | 梁朝偉    |
|  1004 | 1968-07-01  |     1968 | 張國榮    |
|  1001 | 1990-10-10  |     1990 | 路人甲Java  |
+--------+--------------+--------------+---------------+
5 rows in set (0.00 sec)

說明:
year函數(shù):屬于日期函數(shù),可以獲取對應日期中的年份。
上面使用了2種方式排序,第一種是在order by中使用了函數(shù),第二種是使用了別名排序。

where之后進行排序

有訂單數(shù)據(jù)如下:

mysql> drop table if exists t_order;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> create table t_order(
  ->  id int not null auto_increment comment '訂單編號',
  ->  price decimal(10,2) not null default 0 comment '訂單金額',
  ->  primary key(id)
  -> )comment '訂單表';
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t_order (price) values (88.95),(100.68),(500),(300),(20.88),(200.5);
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> select * from t_order;
+----+--------+
| id | price |
+----+--------+
| 1 | 88.95 |
| 2 | 100.68 |
| 3 | 500.00 |
| 4 | 300.00 |
| 5 | 20.88 |
| 6 | 200.50 |
+----+--------+
6 rows in set (0.00 sec)

需求:查詢訂單金額>=100的,按照訂單金額降序排序,顯示2列數(shù)據(jù),列頭:訂單編號、訂單金額,如下:

mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a where a.price>=100 order by a.price desc;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      3 |    500.00 |
|      4 |    300.00 |
|      6 |    200.50 |
|      2 |    100.68 |
+--------------+--------------+
4 rows in set (0.00 sec)

limit介紹

limit用來限制select查詢返回的行數(shù),常用于分頁等操作。

語法:

select 列 from 表 limit [offset,] count;

說明:

  • offset:表示偏移量,通俗點講就是跳過多少行,offset可以省略,默認為0,表示跳過0行;范圍:[0,+∞)。
  • count:跳過offset行之后開始取數(shù)據(jù),取count行記錄;范圍:[0,+∞)。
  • limit中offset和count的值不能用表達式。

下面我們列一些常用的示例來加深理解。

獲取前n行記錄

select 列 from 表 limit 0,n;
或者
select 列 from 表 limit n;

示例,獲取訂單的前2條記錄,如下:

mysql> create table t_order(
  ->  id int not null auto_increment comment '訂單編號',
  ->  price decimal(10,2) not null default 0 comment '訂單金額',
  ->  primary key(id)
  -> )comment '訂單表';
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t_order (price) values (88.95),(100.68),(500),(300),(20.88),(200.5);
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> select * from t_order;
+----+--------+
| id | price |
+----+--------+
| 1 | 88.95 |
| 2 | 100.68 |
| 3 | 500.00 |
| 4 | 300.00 |
| 5 | 20.88 |
| 6 | 200.50 |
+----+--------+
6 rows in set (0.00 sec)
mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a limit 2;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      1 |    88.95 |
|      2 |    100.68 |
+--------------+--------------+
2 rows in set (0.00 sec)
mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a limit 0,2;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      1 |    88.95 |
|      2 |    100.68 |
+--------------+--------------+
2 rows in set (0.00 sec)

獲取最大的一條記錄

我們需要獲取訂單金額最大的一條記錄,可以這么做:先按照金額降序,然后取第一條記錄,如下:

mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a order by a.price desc;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      3 |    500.00 |
|      4 |    300.00 |
|      6 |    200.50 |
|      2 |    100.68 |
|      1 |    88.95 |
|      5 |    20.88 |
+--------------+--------------+
6 rows in set (0.00 sec)
mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a order by a.price desc limit 1;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      3 |    500.00 |
+--------------+--------------+
1 row in set (0.00 sec)
mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a order by a.price desc limit 0,1;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      3 |    500.00 |
+--------------+--------------+
1 row in set (0.00 sec)

獲取排名第n到m的記錄

我們需要先跳過n-1條記錄,然后取m-n+1條記錄,如下:

select 列 from 表 limit n-1,m-n+1;

如:我們想獲取訂單金額最高的3到5名的記錄,我們需要跳過2條,然后獲取3條記錄,如下:

mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a order by a.price desc;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      3 |    500.00 |
|      4 |    300.00 |
|      6 |    200.50 |
|      2 |    100.68 |
|      1 |    88.95 |
|      5 |    20.88 |
+--------------+--------------+
6 rows in set (0.00 sec)
mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a order by a.price desc limit 2,3;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      6 |    200.50 |
|      2 |    100.68 |
|      1 |    88.95 |
+--------------+--------------+
3 rows in set (0.00 sec)

分頁查詢

開發(fā)過程中,分頁我們經(jīng)常使用,分頁一般有2個參數(shù):
page:表示第幾頁,從1開始,范圍[1,+∞)
pageSize:每頁顯示多少條記錄,范圍[1,+∞)
如:page = 2,pageSize = 10,表示獲取第2頁10條數(shù)據(jù)。
我們使用limit實現(xiàn)分頁,語法如下:

select 列 from 表名 limit (page - 1) * pageSize,pageSize;

需求:我們按照訂單金額降序,每頁顯示2條,依次獲取所有訂單數(shù)據(jù)、第1頁、第2頁、第3頁數(shù)據(jù),如下:

mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a order by a.price desc;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      3 |    500.00 |
|      4 |    300.00 |
|      6 |    200.50 |
|      2 |    100.68 |
|      1 |    88.95 |
|      5 |    20.88 |
+--------------+--------------+
6 rows in set (0.00 sec)
mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a order by a.price desc limit 0,2;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      3 |    500.00 |
|      4 |    300.00 |
+--------------+--------------+
2 rows in set (0.00 sec)
mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a order by a.price desc limit 2,2;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      6 |    200.50 |
|      2 |    100.68 |
+--------------+--------------+
2 rows in set (0.00 sec)
mysql> select a.id 訂單編號,a.price 訂單金額 from t_order a order by a.price desc limit 4,2;
+--------------+--------------+
| 訂單編號   | 訂單金額   |
+--------------+--------------+
|      1 |    88.95 |
|      5 |    20.88 |
+--------------+--------------+
2 rows in set (0.00 sec)

避免踩坑

limit中不能使用表達式

mysql> select * from t_order where limit 1,4+1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'limit 1,4+1' at line 1
mysql> select * from t_order where limit 1+0;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'limit 1+0' at line 1
mysql>

結論:limit后面只能夠跟明確的數(shù)字。

limit后面的2個數(shù)字不能為負數(shù)

mysql> select * from t_order where limit -1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'limit -1' at line 1
mysql> select * from t_order where limit 0,-1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'limit 0,-1' at line 1
mysql> select * from t_order where limit -1,-1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'limit -1,-1' at line 1

排序分頁存在的坑

準備數(shù)據(jù):

mysql> insert into test1 (b) values (1),(2),(3),(4),(2),(2),(2),(2);
Query OK, 8 rows affected (0.01 sec)
Records: 8 Duplicates: 0 Warnings: 0
mysql> select * from test1;
+---+---+
| a | b |
+---+---+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 2 |
| 6 | 2 |
| 7 | 2 |
| 8 | 2 |
+---+---+
8 rows in set (0.00 sec)
mysql> select * from test1 order by b asc;
+---+---+
| a | b |
+---+---+
| 1 | 1 |
| 2 | 2 |
| 5 | 2 |
| 6 | 2 |
| 7 | 2 |
| 8 | 2 |
| 3 | 3 |
| 4 | 4 |
+---+---+
8 rows in set (0.00 sec)

下面我們按照b升序,每頁2條數(shù)據(jù),來獲取數(shù)據(jù)。

下面的sql依次為第1頁、第2頁、第3頁、第4頁、第5頁的數(shù)據(jù),如下:

mysql> select * from test1 order by b asc limit 0,2;
+---+---+
| a | b |
+---+---+
| 1 | 1 |
| 2 | 2 |
+---+---+
2 rows in set (0.00 sec)
mysql> select * from test1 order by b asc limit 2,2;
+---+---+
| a | b |
+---+---+
| 8 | 2 |
| 6 | 2 |
+---+---+
2 rows in set (0.00 sec)
mysql> select * from test1 order by b asc limit 4,2;
+---+---+
| a | b |
+---+---+
| 6 | 2 |
| 7 | 2 |
+---+---+
2 rows in set (0.00 sec)
mysql> select * from test1 order by b asc limit 6,2;
+---+---+
| a | b |
+---+---+
| 3 | 3 |
| 4 | 4 |
+---+---+
2 rows in set (0.00 sec)
mysql> select * from test1 order by b asc limit 7,2;
+---+---+
| a | b |
+---+---+
| 4 | 4 |
+---+---+
1 row in set (0.00 sec)

上面有2個問題:

問題1:看一下第2個sql和第3個sql,分別是第2頁和第3頁的數(shù)據(jù),結果出現(xiàn)了相同的數(shù)據(jù),是不是懵逼了。

問題2:整個表只有8條記錄,怎么會出現(xiàn)第5頁的數(shù)據(jù)呢,又懵逼了。

我們來分析一下上面的原因:主要是b字段存在相同的值,當排序過程中存在相同的值時,沒有其他排序規(guī)則時,mysql懵逼了,不知道怎么排序了。

就像我們上學站隊一樣,按照身高排序,那身高一樣的時候如何排序呢?身高一樣的就亂排了。

建議:排序中存在相同的值時,需要再指定一個排序規(guī)則,通過這種排序規(guī)則不存在二義性,比如上面可以再加上a降序,如下:

mysql> select * from test1 order by b asc,a desc;
+---+---+
| a | b |
+---+---+
| 1 | 1 |
| 8 | 2 |
| 7 | 2 |
| 6 | 2 |
| 5 | 2 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
+---+---+
8 rows in set (0.00 sec)
mysql> select * from test1 order by b asc,a desc limit 0,2;
+---+---+
| a | b |
+---+---+
| 1 | 1 |
| 8 | 2 |
+---+---+
2 rows in set (0.00 sec)
mysql> select * from test1 order by b asc,a desc limit 2,2;
+---+---+
| a | b |
+---+---+
| 7 | 2 |
| 6 | 2 |
+---+---+
2 rows in set (0.00 sec)
mysql> select * from test1 order by b asc,a desc limit 4,2;
+---+---+
| a | b |
+---+---+
| 5 | 2 |
| 2 | 2 |
+---+---+
2 rows in set (0.00 sec)
mysql> select * from test1 order by b asc,a desc limit 6,2;
+---+---+
| a | b |
+---+---+
| 3 | 3 |
| 4 | 4 |
+---+---+
2 rows in set (0.00 sec)
mysql> select * from test1 order by b asc,a desc limit 8,2;
Empty set (0.00 sec)

看上面的結果,分頁數(shù)據(jù)都正常了,第5頁也沒有數(shù)據(jù)了。

總結

  • order by … [asc|desc]用于對查詢結果排序,asc:升序,desc:降序,asc|desc可以省略,默認為asc
  • limit用來限制查詢結果返回的行數(shù),有2個參數(shù)(offset,count),offset:表示跳過多少行,count:表示跳過offset行之后取count行
  • limit中offset可以省略,默認值為0
  • limit中offset 和 count都必須大于等于0
  • limit中offset和count的值不能用表達式
  • 分頁排序時,排序不要有二義性,二義性情況下可能會導致分頁結果亂序,可以在后面追加一個主鍵排序

到此這篇關于Mysql排序和分頁(order by&limit)及存在的坑的文章就介紹到這了,更多相關Mysql排序和分頁內容請搜索億速云以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持億速云!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI