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

发布时间:2020-10-16 15:52:15 作者:易兮科技
来源:脚本之家 阅读:183

排序查询(order by)

电商中:我们想查看今天所有成交的订单,按照交易额从高到低排序,此时我们可以使用数据库中的排序功能来完成。

排序语法:

select 字段名 from 表名 order by 字段1 [asc|desc],字段2 [asc|desc];

单字段排序

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 |
+--------+--------+

按函数排序

有学生表(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函数:属于日期函数,可以获取对应日期中的年份。
上面使用了2种方式排序,第一种是在order by中使用了函数,第二种是使用了别名排序。

where之后进行排序

有订单数据如下:

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列数据,列头:订单编号、订单金额,如下:

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查询返回的行数,常用于分页等操作。

语法:

select 列 from 表 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)

分页查询

开发过程中,分页我们经常使用,分页一般有2个参数:
page:表示第几页,从1开始,范围[1,+∞)
pageSize:每页显示多少条记录,范围[1,+∞)
如:page = 2,pageSize = 10,表示获取第2页10条数据。
我们使用limit实现分页,语法如下:

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

需求:我们按照订单金额降序,每页显示2条,依次获取所有订单数据、第1页、第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 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后面只能够跟明确的数字。

limit后面的2个数字不能为负数

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

排序分页存在的坑

准备数据:

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条数据,来获取数据。

下面的sql依次为第1页、第2页、第3页、第4页、第5页的数据,如下:

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页的数据,结果出现了相同的数据,是不是懵逼了。

问题2:整个表只有8条记录,怎么会出现第5页的数据呢,又懵逼了。

我们来分析一下上面的原因:主要是b字段存在相同的值,当排序过程中存在相同的值时,没有其他排序规则时,mysql懵逼了,不知道怎么排序了。

就像我们上学站队一样,按照身高排序,那身高一样的时候如何排序呢?身高一样的就乱排了。

建议:排序中存在相同的值时,需要再指定一个排序规则,通过这种排序规则不存在二义性,比如上面可以再加上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)

看上面的结果,分页数据都正常了,第5页也没有数据了。

总结

到此这篇关于Mysql排序和分页(order by&limit)及存在的坑的文章就介绍到这了,更多相关Mysql排序和分页内容请搜索亿速云以前的文章或继续浏览下面的相关文章希望大家以后多多支持亿速云!

推荐阅读:
  1. MySQL 排序
  2. oracle和mysql分页的方法有什么不同

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

mysql 排序 分页

上一篇:06-GPIO实验

下一篇:Tornado 多进程实现分析详解

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》