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)将表中的信息进行联合。