玩转Mysql系列 - 第8篇:详解排序和分页(order by & limit),及存在的坑

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

说明:

offset:表示偏移量,通俗点讲就是跳过多少行,offset可以省略,默认为0,表示跳过0行;范围:[0,+∞)。

count:跳过offset行之后开始取数据,取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)

分页查询

开发过程中,分页我们经常使用,分页一般有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页也没有数据了。

难道这样就够了吗?不,远远不够!

提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。

备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记

我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。

今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!

阿里一面就落马,恶补完这份“阿里面试宝典”后,上岸蚂蚁金服

阿里一面就落马,恶补完这份“阿里面试宝典”后,上岸蚂蚁金服

image.png

加入社区:https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0
±–±–+

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页也没有数据了。

难道这样就够了吗?不,远远不够!

提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。

备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记

我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。

今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!

[外链图片转存中…(img-IYuvGyN3-1725612421685)]

[外链图片转存中…(img-h1YyOixZ-1725612421686)]

[外链图片转存中…(img-bIM5q21p-1725612421686)]

加入社区:https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值