网站建设知识
MySQL快速入门10
2025-07-22 10:00  点击:0

order by

Order by,可以使用一列或者多个列对结果进行排序。
如果存在多个排序字段,在前一个不能比较出结果后,后边的才起作用
可以分别指明是升序还是降序:asc(ascending) desc(descending)
用法:
[ORDER BY {col_name | expr | position} [ASC | DESC] , ...]

注意: 是对检索出来的字段进行排序,一定要在where之后如果是分组,则应该使用对分组字段进行排序的groupby语法。
mysql> select * from teacher_class where 1 order by days;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 ||  2 | 韩信       | male   | php0228 | 106  |   18 | 2013-02-28 | 2013-03-30 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  1 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 ||  5 | 李白       | male   | php0228 | 204  |   21 | 2013-03-31 | 2013-04-29 ||  3 | 韩信       | male   | php0331 | 102  |   24 | 2013-03-31 | 2013-05-05 |+----+--------+--------+---------+------+------+------------+------------+6 rows in set (0.00 sec)mysql> select * from teacher_class where 1 order by days desc;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  3 | 韩信       | male   | php0331 | 102  |   24 | 2013-03-31 | 2013-05-05 ||  1 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 ||  5 | 李白       | male   | php0228 | 204  |   21 | 2013-03-31 | 2013-04-29 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  2 | 韩信       | male   | php0228 | 106  |   18 | 2013-02-28 | 2013-03-30 ||  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 |+----+--------+--------+---------+------+------+------------+------------+6 rows in set (0.00 sec)
上述代码可以看出,默认是升序的。

mysql> select t_name, days from teacher_class where 1 group by t_name order by days desc;+--------+------+| t_name | days |+--------+------+| 韩信       |   21 || 李白       |   20 || 韩非       |   15 |+--------+------+3 rows in set (0.00 sec)
order by对分组的数据进行排序是无效的,必须经过group by内部的排序才有效!
解决方法
mysql> select * from    -> (select t_name as name, sum(days) as day from teacher_class group by t_name) as tb    -> order by day;+------+------+| name | day  |+------+------+| 韩非     |   15 || 李白     |   41 || 韩信     |   63 |+------+------+3 rows in set (0.00 sec)mysql> select * from    -> (select t_name as name, sum(days) as day from teacher_class group by t_name) as tb    -> order by day desc;+------+------+| name | day  |+------+------+| 韩信     |   63 || 李白     |   41 || 韩非     |   15 |+------+------+3 rows in set (0.00 sec)

先通过t_name对表进行分组,(注意,分组中的表一定要使用别名),然后再对分组的表进行group by排序,注意,这里使用的是别名!
对多个字段进行排序(只有前一个字段排序无效的时候,才会在后一个字段进行排序):



limit


Limit子句可以被用于限制被SELECT语句返回的行数.
用法:
[LIMIT {[offset,] row_count | row_count OFFSET offset}]

Limit offset,row_count Offset 偏移量,从0开始。可以省略,默认为0.(也就是下边索引是从0开始的)Row_count 总记录数,如果数量大于,余下的记录数,则获取所有余下的即可:
表示从offset索引位置开始获取row_count条记录。
可以省略offset,默认为0. limit row_count == limit 0, row_count;

mysql> select * from teacher_class limit 3,4;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  5 | 李白       | male   | php0228 | 204  |   21 | 2013-03-31 | 2013-04-29 ||  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 |+----+--------+--------+---------+------+------+------------+------------+3 rows in set (0.00 sec)
从索引行第三行开始,截取四行数据,也就是截取3,4,5,6行数据(索引从0开始)。
mysql> select * from teacher_class limit 5;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  1 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 ||  2 | 韩信       | male   | php0228 | 106  |   18 | 2013-02-28 | 2013-03-30 ||  3 | 韩信       | male   | php0331 | 102  |   24 | 2013-03-31 | 2013-05-05 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  5 | 李白       | male   | php0228 | 204  |   21 | 2013-03-31 | 2013-04-29 |+----+--------+--------+---------+------+------+------------+------------+5 rows in set (0.00 sec)
从第0行开始,截取前五行数据;

mysql> select * from teacher_class limit 5, 100;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 |+----+--------+--------+---------+------+------+------------+------------+1 row in set (0.00 sec)
当行数大于剩下的所有行数时,获取所有剩下的行数。
mysql> select * from teacher_class order by days desc limit 1;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  3 | 韩信       | male   | php0331 | 102  |   24 | 2013-03-31 | 2013-05-05 |+----+--------+--------+---------+------+------+------------+------------+1 row in set (0.00 sec)
获取天数最多的一行数据。

distinct


去除重复记录,

所谓重复的记录,指的是字段值都相同的记录,而不是部分字段相同的记录。

mysql> select * from teacher_class;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  1 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 ||  2 | 韩信       | male   | php0228 | 106  |   18 | 2013-02-28 | 2013-03-30 ||  3 | 韩信       | male   | php0331 | 102  |   24 | 2013-03-31 | 2013-05-05 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  5 | 李白       | male   | php0228 | 204  |   21 | 2013-03-31 | 2013-04-29 ||  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 |+----+--------+--------+---------+------+------+------------+------------+

mysql> select distinct t_name from teacher_class;+--------+| t_name |+--------+| 韩信       || 李白       || 韩非       |+--------+3 rows in set (0.00 sec)
所有名字都不相同的记录。

mysql> select distinct t_name,gender from teacher_class;+--------+--------+| t_name | gender |+--------+--------+| 韩信       | male   || 李白       | male   || 韩非       | secret |+--------+--------+3 rows in set (0.00 sec)
名字和型别都不相同的记录。


all


和distinct相似,只不过他是返回所有的记录。
mysql> select all t_name from teacher_class;+--------+| t_name |+--------+| 韩信       || 韩信       || 韩信       || 李白       || 李白       || 韩非       |+--------+6 rows in set (0.00 sec)

其实默认的就是all操作,所以加不加all都是一样的。
mysql> select t_name from teacher_class;+--------+| t_name |+--------+| 韩信       || 韩信       || 韩信       || 李白       || 李白       || 韩非       |+--------+6 rows in set (0.00 sec)

union


UNION用于把来自许多SELECT语句的结果组合到一个结果集合中。
用法:
SELECT ...UNION [ALL | DISTINCT]SELECT ...[UNION [ALL | DISTINCT]SELECT ...]

获得每一个班级内代课最多的讲师。

注意:
数据列是根据列而不是根据名字进行匹配的。
在第一个SELECT语句中被使用的列名称被用于结果的列名称
默认情况下,会去除重复的数据行,可以使用union all保留重复的数据行。
如要对union的结果作为整体进行排序或limit,(最好对单个地SELECT语句加圆括号),在后边增加order by 或limit。order by引用的数据列来自第一个select。
分别排序,再联合,则需要用括号将各select语句括起来,且order by只能在limit 出现时才有效。


获取php0115班和php0228班数代课天数最多的两个老师的记录:
mysql> (select * from teacher_class where c_name='php0115' order by days desc limit 1)    -> union    -> (select * from teacher_class where c_name='php0228' order by days desc limit 1);+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  1 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 ||  5 | 李白       | male   | php0228 | 204  |   21 | 2013-03-31 | 2013-04-29 |+----+--------+--------+---------+------+------+------------+------------+2 rows in set (0.01 sec)

应用场景:获得数据的条件,出现逻辑冲突,或者很难在一个逻辑内表示,就可以拆分成 多个逻辑,分别实现,最后将结果合并到一起。

union all



获得0115班所有代课教师,结果按照代课天数升序排序,同时需要获得0228班,结果按照降序排序,(一个降序一个升序)

注意,如果union 的结果存在重复的记录,那么会消除重复.可以通过 union选项 all 达到目的
mysql> (select t_name, days, c_name from teacher_class where c_name='php0115' order by days asc)    -> union    -> (select t_name, days, c_name from teacher_class where c_name='php0228' order by days desc);+--------+------+---------+| t_name | days | c_name  |+--------+------+---------+| 韩信       |   21 | php0115 || 李白       |   20 | php0115 || 韩非       |   15 | php0115 || 韩信       |   18 | php0228 || 李白       |   21 | php0228 |+--------+------+---------+5 rows in set (0.00 sec)


上述只有五条记录。
mysql> (select t_name, days, c_name from teacher_class where c_name='php0115' order by days asc)    -> union all    -> (select t_name, days, c_name from teacher_class where c_name='php0228' order by days desc);+--------+------+---------+| t_name | days | c_name  |+--------+------+---------+| 韩信       |   21 | php0115 || 李白       |   20 | php0115 || 韩非       |   15 | php0115 || 韩信       |   21 | php0115 || 韩信       |   18 | php0228 || 李白       |   21 | php0228 |+--------+------+---------+6 rows in set (0.00 sec)
上述却又六条记录。
另外一点,上述代码并没有对数据进行排序!因为不加limit,order by不起作用。 将子句包裹在子括号中,子语句的order by只有配合limit时,才会生效。union在做子语句时,会对没有limit子句进行优化,也就是忽略掉order by。
mysql> (select t_name, days, c_name from teacher_class where c_name='php0115')    -> union all    -> (select t_name, days, c_name from teacher_class where c_name='php0228') order by days desc;+--------+------+---------+| t_name | days | c_name  |+--------+------+---------+| 韩信       |   21 | php0115 || 李白       |   21 | php0228 || 韩信       |   21 | php0115 || 李白       |   20 | php0115 || 韩信       |   18 | php0228 || 韩非       |   15 | php0115 |+--------+------+---------+6 rows in set (0.00 sec)
在合并的记录最后进行统一降序排序。

注意: select子语句加括号并不是必须的;多个selec子语句所检测到的字段数,必须一致,且数据类型也要要求一致,但是mysql内部会进行类型转换处理,但前提是转换必须成功!
mysql> (select t_name, days, c_name from teacher_class where c_name='php0115')    -> union all    -> (select days, t_name, c_name from teacher_class where c_name='php0228') order by days    -> ;+--------+------+---------+| t_name | days | c_name  |+--------+------+---------+| 韩非       | 15   | php0115 || 李白       | 20   | php0115 || 韩信       | 21   | php0115 || 韩信       | 21   | php0115 || 21     | 李白     | php0228 || 18     | 韩信     | php0228 |+--------+------+---------+6 rows in set (0.00 sec)
发生了数据类型的转换!

subquery子查询





子查询,指的是一个查询语句被其他语句包裹。

分类:
一个子查询会返回一个标量(单一值)、一个行、一个列或一个表(一行或多行及一列或多列)。
这些子查询被称为标量、列、行和表子查询。

根据子查询select 出现的的位置不同
Where型子查询,from型子查询

使用:
子查询和外部查询可以是任意表,不要求是同表。

语法:
子查询必须位于小括号中。
子查询外部语句可以是:SELECT, INSERT, UPDATE, DELETE, SET或DO
不能在子查询时修改。
子查询返回值:




标量子查询,查询返回单一值。
列子查询:返回值是一列值。
行子查询:返回一个行。
表子查询:返回多个行。
子查询出现的位置:

标量子查询


标量,语法:
non_subquery_operand comparison_operator (subquery)

可以使用的运算符:
= > < >= <= <>
首先向teacher_class中插入一行数据:
mysql> insert into teacher_class values    -> (null, '李宁', 'male', 'php0331', '102', 24, '2013-03-31', '2013-05-05');Query OK, 1 row affected (0.03 sec)

此时表中的数据:
mysql> select * from teacher_class;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  1 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 ||  2 | 韩信       | male   | php0228 | 106  |   18 | 2013-02-28 | 2013-03-30 ||  3 | 韩信       | male   | php0331 | 102  |   24 | 2013-03-31 | 2013-05-05 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  5 | 李白       | male   | php0228 | 204  |   21 | 2013-03-31 | 2013-04-29 ||  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 ||  7 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 ||  8 | 李宁       | male   | php0331 | 102  |   24 | 2013-03-31 | 2013-05-05 |+----+--------+--------+---------+------+------+------------+------------+8 rows in set (0.00 sec)

如何获得,代课最多的老师呢?(如果有多个老师代课天数一致,都是最大值如何处理呢?)
mysql> select * from teacher_class order by days desc limit 1;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  3 | 韩信       | male   | php0331 | 102  |   24 | 2013-03-31 | 2013-05-05 |+----+--------+--------+---------+------+------+------------+------------+1 row in set (0.00 sec)

可是现在有两个老师的授课天数是24,那怎么选中这两个呢?如果不知道到底有几个老师并列呢?
换个思路:先获得最多的代课天数是多少天,
Select max(days) from teacher_class;
再 判读哪个老师的代课天数和最大值是一样的。
mysql允许将上面的查询结果,作为一个值来使用。
Var1 = Select max(days) from teacher_class;保存起来
Select t_name, gender from teacher_class where days = var1;

先将这两步合并起来一起使用:
mysql> select * from teacher_class where days=(select max(days) from teacher_class);+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  3 | 韩信       | male   | php0331 | 102  |   24 | 2013-03-31 | 2013-05-05 ||  8 | 李宁       | male   | php0331 | 102  |   24 | 2013-03-31 | 2013-05-05 |+----+--------+--------+---------+------+------+------------+------------+2 rows in set (0.02 sec)


列子查询


强调一列,通常为多个行的一列值。
mysql> select * from teacher_class where t_name in (select t_name from teacher_class where c_name = 'php0228');+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  1 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 ||  2 | 韩信       | male   | php0228 | 106  |   18 | 2013-02-28 | 2013-03-30 ||  3 | 韩信       | male   | php0331 | 102  |   24 | 2013-03-31 | 2013-05-05 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  5 | 李白       | male   | php0228 | 204  |   21 | 2013-03-31 | 2013-04-29 ||  7 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 |+----+--------+--------+---------+------+------+------------+------------+6 rows in set (0.00 sec)
首先进行子查询找到班级名为php0228的授课老师名字,然后在表中查询名字为这两个老师的所有的表记录。
mysql> select * from teacher_class where t_name=any (select t_name from teacher_class where c_name = 'php0228');
这句话和上句话返回结果是一样的。

集合运算符:



列:
operand IN|NOT IN (subquery)
满足数据中的任意一个,返回真。都不满足返回假。
operand comparison_operator ANY (subquery)
operand comparison_operator SOME (subquery)
数据中的任何一个。=Any相当于in。而!=any 不是 not in。 意义是只要不等于其中任何一个即可。
Some 和 any是别名。因为 英语人,不能理解 not equal any(!=any) 的含义,not equal some(!=some)英语人知道。
operand comparison_operator ALL (subquery)
全部匹配,!=all为not in;

行:
单行
(字段1,字段2) = (select 字段1,字段2 from 表 limit 1)
多行(表) in
(字段1,字段2) = (select 字段1, 字段2 from 表 );
与某老师具有同样代课经历的所有讲师(同一个班,同一个教室)