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

select 语法:

select select_expr [from tbl_name] [where] [group by] [having] [order by] [limit]
select [查询选项] [查询表达式(字段表达式)] [from 子句] [where 子句] [group by 子句] [having 子句] [order by 子句] [limit 子句]
注意:select 子句可以不出现,如果出现则必须按照顺序出现!

创建新表teacher_class:

mysql> create table teacher_class (    -> id int primary key auto_increment,    -> t_name varchar(10),    -> gender enum('female', 'male', 'secret'),    -> c_name char(7),    -> room char(3),    -> days tinyint unsigned,    -> begin_date date,    -> end_date date    -> ) character set utf8;Query OK, 0 rows affected (0.06 sec)

向新表中插入数据:

insert into teacher_class values(null, '韩信', 'male', 'php0115', '207', 21, '2013-01-15', '2013-02-20'),(null, '韩信', 'male', 'php0228', '106', 18, '2013-02-28', '2013-03-30'),(null, '韩信', 'male', 'php0331', '102', 24, '2013-03-31', '2013-05-05'),(null, '李白', 'male', 'php0115', '207', 20, '2013-02-22', '2013-03-25'),(null, '李白', 'male', 'php0228', '204', 21, '2013-03-31', '2013-04-29'),(null, '韩非', 'secret', 'php0115', '207', 15, '2013-03-27', '2013-04-18');

数据展示:

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 |+----+--------+--------+---------+------+------+------------+------------+6 rows in set (0.02 sec)


表达式:


查询列可以是一个列名,表达式都可以。每个列之间使用逗号分割。
字段也是可以参与运算的,数据是保存在字段内的,因此可以将字段当作变量来看待。
AS Alias可以为每一个列指明一个别名,可用于group by ,having 或 order by 子句。
其中AS是可以选用的,但是建议使用。不使用可能会出现 field1 field2没有写逗号分割,导致将第二个认为是第一个的别名。


字段(变量),函数返回值:
mysql> select 10+20;+-------+| 10+20 |+-------+|    30 |+-------+1 row in set (0.00 sec)

mysql> select now();+---------------------+| now()               |+---------------------+| 2016-08-05 20:00:20 |+---------------------+1 row in set (0.02 sec)

mysql> select now(), unix_timestamp();+---------------------+------------------+| now()               | unix_timestamp() |+---------------------+------------------+| 2016-08-05 20:03:31 |       1470398611 |+---------------------+------------------+1 row in set (0.03 sec)

mysql> select now() time, unix_timestamp() 时间戳;+---------------------+------------+| time                | 时间戳          |+---------------------+------------+| 2016-08-05 20:04:09 | 1470398649 |+---------------------+------------+1 row in set (0.00 sec)


列子句:


如果是从表中获得数据,那么字段,就是变量,可以参与任何运算(concat函数将字符串连接起来):
mysql> select id, concat(t_name, '-', gender), c_name from teacher_class;+----+-----------------------------+---------+| id | concat(t_name, '-', gender) | c_name  |+----+-----------------------------+---------+|  1 | 韩信-male                       | php0115 ||  2 | 韩信-male                       | php0228 ||  3 | 韩信-male                       | php0331 ||  4 | 李白-male                       | php0115 ||  5 | 李白-male                       | php0228 ||  6 | 韩非-secret                     | php0115 |+----+-----------------------------+---------+6 rows in set (0.00 sec)


别名as


常一个表达式,形式不够良好,不容易读取;起一个 可以容易读取的别名即可:使用 关键字 AS
标识符 [as] 别名

注意:as可以省略,一个字段后面的标识符,就是当前的别名
建议不要忽略别名关键字as!
mysql> select id as 标号, t_name 姓名 from teacher_class;+------+------+| 标号     | 姓名     |+------+------+|    1 | 韩信     ||    2 | 韩信     ||    3 | 韩信     ||    4 | 李白     ||    5 | 李白     ||    6 | 韩非     |+------+------+6 rows in set (0.00 sec)
注意:当字符串中出现空格的时候需要使用单引号!

From子句


表示查询的目标数据源,通常情况下是表名(也支持别名)。

mysql> select id, t_name from teacher_class 表;+----+--------+| id | t_name |+----+--------+|  1 | 韩信       ||  2 | 韩信       ||  3 | 韩信       ||  4 | 李白       ||  5 | 李白       ||  6 | 韩非       |+----+--------+6 rows in set (0.00 sec)

表名也是一个列表:如果没有任何条件的两个表名,会得到 表1乘表2内的所有数据。交叉连接,笛卡尔积

如teacher_class中有六行数据,auin_1中有八行数据,那么接下来就有48行数据:
mysql> select * from teacher_class,auin_1;
48 rows in set (0.00 sec)
中间表中的数据没有列出。
表名可以是tbl_name或者db_name.tbl_name。

表可以是一个或者多个,使用逗号分割(参考多表操作)

虚拟表dual


可以不存在表名,此时可以使用一个dual作为伪表名,来保证sql语法的兼容性(有些服务器要求必须有表名)。

mysql> select now() from dual;+---------------------+| now()               |+---------------------+| 2016-08-05 20:16:56 |+---------------------+1 row in set (0.00 sec)

不建表而进行相关函数的查询工作。
From 可以省略,但是有些服务器是不允许省略。 mysql支持使用dual作为虚拟表。



运算符




常用的运算符: 等于:=
不等于:<> !=
小于,小于等于,大于,大于等于:< <= > >=
模糊匹配:like ‘pattern’ ,通配符_表示单个字符%表示任意字符的任意组合\%转义%. \_转义_
布尔判断:is 布尔值|is not 布尔值。布尔值可以为 true,false
Null值判断:is null | Is not null。还可以使用 ISNULL()
NULL-Safe等于:与=相同,不过支持null运算。<=> null <=> null 1 null <=> other 0
范围:expr BETWEEN min AND max 。闭区间(大于等于,小于等于)。 (min <= expr AND expr <= max)
不在某个区间:expr NOT BETWEEN min AND max 。NOT(expr BETWEEN min AND max)
在集合内:expr IN (value,...)
不在集合内:expr NOT IN (value,...)
返回指定位置:INTERVAL(N,N1,N2,N3,...)
返回最小值:LEAST(value1,value2,...)
返回最大值:GREATEST(value1,value2,...)
找到第一个非零的值:COALESCE(value,...)

逻辑运算符:
非:not !,非null 为null。
与:and &&,有0就是0,都是非零为1,存在null与非零则为null。
或:or || , null||null=null null||1=1 null||0=null
异或: xor ,有null,就是null。

优先级
运算符的组合,也支持优先级,可以使用小括号完成定义优先级。
mysql> select null is not null, null is null;+------------------+--------------+| null is not null | null is null |+------------------+--------------+|                0 |            1 |+------------------+--------------+1 row in set (0.00 sec)
判断null值用is null或者is not null。

<=> 功能与 =一致,特别的功能在于 可以比较null值。

mysql> select null <=> null, 10 <=> null;+---------------+-------------+| null <=> null | 10 <=> null |+---------------+-------------+|             1 |           0 |+---------------+-------------+1 row in set (0.02 sec)

between A and B,取A和B之间的数值,包含A和B
mysql> select * from teacher_class where days between 15 and 20;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  2 | 韩信       | male   | php0228 | 106  |   18 | 2013-02-28 | 2013-03-30 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 |+----+--------+--------+---------+------+------+------------+------------+3 rows in set (0.00 sec)

另外一种表示方法:
mysql> select * from teacher_class where days<=20 and days>=15;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  2 | 韩信       | male   | php0228 | 106  |   18 | 2013-02-28 | 2013-03-30 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 |+----+--------+--------+---------+------+------+------------+------------+3 rows in set (0.00 sec)

另外一种方式方法:
mysql> select * from teacher_class where days<=20 && days>=15;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  2 | 韩信       | male   | php0228 | 106  |   18 | 2013-02-28 | 2013-03-30 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 |+----+--------+--------+---------+------+------+------------+------------+3 rows in set (0.00 sec)


in代表在集合之内,取出天数在15、18、20的表的信息:
mysql> select * from teacher_class where days in (15, 18,20);+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  2 | 韩信       | male   | php0228 | 106  |   18 | 2013-02-28 | 2013-03-30 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 |+----+--------+--------+---------+------+------+------------+------------+3 rows in set (0.00 sec)

interval获取一个元素的索引: Interval(值, 元素1, 元素2, 元素N);
依次判断值,与元素之间的大小关系,如果值小于元素1,则返回0;
如果值小于元素2 则返回1,依次类推。
mysql> select t_name, days, interval(days, 10, 20, 30) from teacher_class where interval(days,10,20,30)=1;+--------+------+----------------------------+| t_name | days | interval(days, 10, 20, 30) |+--------+------+----------------------------+| 韩信       |   18 |                          1 || 韩非       |   15 |                          1 |+--------+------+----------------------------+
上述代码显示出days大于等于10小于20的表的结构。
逻辑运算符:
And &&
Or ||
Not !
Xor

逻辑运算符与null的运算:
非:not !,非null 为null
与:and &&,有0就是0,都是非零为1,存在null与非零则为null
或:or || , null||null=null null||1=1 null||0=null
异或: xor ,有null,就是null

mysql> select !null;+-------+| !null |+-------+|  NULL |+-------+1 row in set (0.00 sec)

mysql> select null;+------+| NULL |+------+| NULL |+------+1 row in set (0.00 sec)

mysql> select 0 && null;+-----------+| 0 && null |+-----------+|         0 |+-----------+1 row in set (0.00 sec)

mysql> select 1 && null;+-----------+| 1 && null |+-----------+|      NULL |+-----------+1 row in set (0.00 sec)

mysql> select null || 1;+-----------+| null || 1 |+-----------+|         1 |+-----------+1 row in set (0.00 sec)mysql> select null || 0;+-----------+| null || 0 |+-----------+|      NULL |+-----------+1 row in set (0.00 sec)mysql> select null || null;+--------------+| null || null |+--------------+|         NULL |+--------------+1 row in set (0.00 sec)


group by子句


Group by 根据一个或多个列对结果集进行分组,语法:
[GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]]

分组后,每组内显示一条记录:
原则上,分组后,查询字段应该只有分组字段,但是可以有其他字段。此时其他字段就只是组内第一条记录的信息,不能准确表示组内所有数据信息,因此通常不查询其他字段。

分组后会利用分组字段进行排序显示结果,默认为asc升序,可以修改为desc降序。

可以使用多个字段进行分组,每个字段可以设置排序规则。

可以使用with rollup 进行组内聚合计算。

mysql> select t_name, gender, sum(days) from teacher_class where 1 group by t_name;+--------+--------+-----------+| t_name | gender | sum(days) |+--------+--------+-----------+| 李白       | male   |        41 || 韩信       | male   |        63 || 韩非       | secret |        15 |+--------+--------+-----------+3 rows in set (0.02 sec)
以上代码表明姓名相同的数据显示在同一格上边,并统计天数之和。
注意:如果合计函数使用时,没有与groupby 配合,统计所有的数据,将所有的数据当作一组。

mysql> select sum(days) from teacher_class where 1;+-----------+| sum(days) |+-----------+|       119 |+-----------+1 row in set (0.01 sec)

默认是升序的asc,可以使用group by时修改为降序desc
mysql> select * from teacher_class where 1 group by t_name order by days asc;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  1 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 |+----+--------+--------+---------+------+------+------------+------------+


mysql> select * from teacher_class where 1 group by t_name order by days desc;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  1 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 ||  6 | 韩非       | secret | php0115 | 207  |   15 | 2013-03-27 | 2013-04-18 |+----+--------+--------+---------+------+------+------------+------------+3 rows in set (0.00 sec)

使用组合字段进行分组,
mysql> select t_name,c_name, sum(days) from teacher_class where 1 group by t_name, c_name;+--------+---------+-----------+| t_name | c_name  | sum(days) |+--------+---------+-----------+| 李白       | php0115 |        20 || 李白       | php0228 |        21 || 韩信       | php0115 |        21 || 韩信       | php0228 |        18 || 韩信       | php0331 |        24 || 韩非       | php0115 |        15 |+--------+---------+-----------+6 rows in set (0.00 sec)
上述代码表明只有t_name和c_name都相同的才会分为一组。


rollup
使用 with rollup ,可以相当于利用组合条进行统计后,再使用上一条件再次统计一次。

mysql> select t_name,c_name, sum(days) from teacher_class where 1 group by t_name, c_name with rollup    ->    -> ;+--------+---------+-----------+| t_name | c_name  | sum(days) |+--------+---------+-----------+| 李白       | php0115 |        20 || 李白       | php0228 |        21 || 李白       | NULL    |        41 || 韩信       | php0115 |        21 || 韩信       | php0228 |        18 || 韩信       | php0331 |        24 || 韩信       | NULL    |        63 || 韩非       | php0115 |        15 || 韩非       | NULL    |        15 || NULL   | NULL    |       119 |+--------+---------+-----------+10 rows in set (0.00 sec)
注意,会统计到 没有分组的情况,整个都是一组的情况: 上述代码,李白、韩信、韩非分别又统计了一次,整个表由重新统计了一次,不相同的部分用NULL表示。
是否可以得到 大于某些代课天数的讲师信息?
mysql> select t_name, sum(days) from teacher_class where sum(days)>=35 group by t_name;ERROR 1111 (HY000): Invalid use of group function

分析发现:
where先执行,group by 后执行。sum()在计算的时候,没有分组的呢。无法在在where内使用合计函数:

having子句


参考select语句的执行顺序:
From -> where -> select -> group by ->
可以知道,where负责先获得结果,而如果需要在结果中再次处理(例如通过结果统计出来的聚合结果),则不能再使用where,此时where已经执行完毕,因此此时SQL提供给应该使用having再次执行过滤操作。
在 SQL 中增加 HAVING 子句原因是,WHERE 关键字无法与合计函数一起使用。
having与where类似,可筛选数据,where后的表达式怎么写,having就怎么写。不过having可以使用字段别名

having子句负责在结果(where查询到的)中进行再次过滤,可以像使用where一样,having进行处理:
mysql> select * from teacher_class where days >=20;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  1 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 ||  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 |+----+--------+--------+---------+------+------+------------+------------+4 rows in set (0.00 sec)


mysql> select * from teacher_class where days >=20 having room=207;+----+--------+--------+---------+------+------+------------+------------+| id | t_name | gender | c_name  | room | days | begin_date | end_date   |+----+--------+--------+---------+------+------+------------+------------+|  1 | 韩信       | male   | php0115 | 207  |   21 | 2013-01-15 | 2013-02-20 ||  4 | 李白       | male   | php0115 | 207  |   20 | 2013-02-22 | 2013-03-25 |+----+--------+--------+---------+------+------+------------+------------+2 rows in set (0.00 sec)
having子句负责在where已经过滤的数据基础之上进一步过滤。
mysql> select t_name, sum(days) from teacher_class where 1 group by t_name having sum(days)>35;+--------+-----------+| t_name | sum(days) |+--------+-----------+| 李白       |        41 || 韩信       |        63 |+--------+-----------+2 rows in set (0.00 sec)



集合函数







平均值:AVG([DISTINCT] expr)
统计数目:COUNT(expr),统计非null值的数目 count(*)可以返回所有的记录
最大最小值:MIN([DISTINCT] expr), MAX([DISTINCT] expr)
计算总和:SUM([DISTINCT] expr)
组内连接:GROUP_ConCAT(expr)

合计函数通常与group by 一起使用,用于统计组内的信息。
但是可以单独使用,相当于将所有行看成一组。

通常合计函数是不统计null值的。


mysql> select t_name, sum(days) from teacher_class where 1 group by t_name having sum(days)>35;+--------+-----------+| t_name | sum(days) |+--------+-----------+| 李白       |        41 || 韩信       |        63 |+--------+-----------+2 rows in set (0.00 sec)mysql> select t_name, avg(days) from teacher_class where 1 group by t_name;+--------+-----------+| t_name | avg(days) |+--------+-----------+| 李白       |   20.5000 || 韩信       |   21.0000 || 韩非       |   15.0000 |+--------+-----------+3 rows in set (0.00 sec)mysql> select t_name, max(days) from teacher_class where 1 group by t_name;+--------+-----------+| t_name | max(days) |+--------+-----------+| 李白       |        21 || 韩信       |        24 || 韩非       |        15 |+--------+-----------+3 rows in set (0.00 sec)mysql> select t_name, min(days) from teacher_class where 1 group by t_name;+--------+-----------+| t_name | min(days) |+--------+-----------+| 李白       |        20 || 韩信       |        18 || 韩非       |        15 |+--------+-----------+3 rows in set (0.00 sec)mysql> select t_name, count(days) from teacher_class where 1 group by t_name;+--------+-------------+| t_name | count(days) |+--------+-------------+| 李白       |           2 || 韩信       |           3 || 韩非       |           1 |+--------+-------------+3 rows in set (0.00 sec)


mysql> select count(*) from teacher_class;+----------+| count(*) |+----------+|        6 |+----------+1 row in set (0.00 sec)

mysql> select t_name, max(days) from teacher_class;+--------+-----------+| t_name | max(days) |+--------+-----------+| 韩信       |        24 |+--------+-----------+1 row in set (0.00 sec)
从所有行中挑选出天数做最大的一个。
mysql> select avg(days) from teacher_class;+-----------+| avg(days) |+-----------+|   19.8333 |+-----------+1 row in set (0.00 sec)
统计出所有的人数平均的天数。

mysql> select t_name, concat(t_name, id) from teacher_class;+--------+--------------------+| t_name | concat(t_name, id) |+--------+--------------------+| 韩信       | 韩信1                  || 韩信       | 韩信2                  || 韩信       | 韩信3                  || 李白       | 李白4                  || 李白       | 李白5                  || 韩非       | 韩非6                  |+--------+--------------------+6 rows in set (0.00 sec)
将每一行数据进行联合

mysql> select t_name, group_concat(t_name, id) from teacher_class;+--------+-------------------------------------+| t_name | group_concat(t_name, id)            |+--------+-------------------------------------+| 韩信       | 韩信1,韩信2,韩信3,李白4,李白5,韩非6+--------+-------------------------------------+1 row in set (0.00 sec)
将表中的信息进行联合。