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 表 );
与某老师具有同样代课经历的所有讲师(同一个班,同一个教室)