MySQL语句的执行顺序如下:
执行序号 | 执行操作 | 解释 |
---|---|---|
1 | from | 对from的左边的表的输出,会作为右边的表的输入计算笛卡尔积得到虚拟表T1 |
2 | on | 对虚表T1进行on过滤,过滤出所有满足on谓词条件的列,生成虚拟表T2 |
3 | join | 如果指定了outer join(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表T2中,产生虚拟表T3, from子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为止。 |
4 | where | 对虚拟表T3进行where条件过滤。只有符合<where-condition>的记录才会被插入到虚拟表T4中 |
5 | group by | 根据group by子句中的列,对T4中的记录进行分组操作,产生T5 |
6 | with (cube、rollup) | 对表T5进行cube或者rollup操作,产生表T6 |
7 | having | 对虚拟表T6应用having过滤,只有符合<having-condition>的记录才会被 插入到虚拟表T7中 |
8 | select | 执行select操作,选择指定的列,插入到虚拟表T8中 |
9 | distinct | 对T8中的记录进行去重。产生虚拟表T9 |
10 | order by | 将虚拟表T9中的记录按照<order_by_list>进行排序操作,产生虚拟表T10 |
11 | limit | 取出指定行的记录,产生虚拟表T11, 并将结果返回 |
查询子句
命令格式: select [all|distinct] select_expr from -> where -> group by [合计函数] -> having -> order by -> limit
select_expr
ex:
-- 可以用 * 表示所有字段。
select * from student;
-- 可以使用表达式(计算公式、函数调用、字段也是个表达式)
select name, age,512*2, now() from student;
-- 可以为每个列使用别名。适用于简化列标识,避免多个列标识符重复。使用 as 关键字,也可省略 as.
select age as student_age from student;
from 子句
用于标识查询来源。
ex:
-- 可以为表起别名。使用as关键字,也可以省略as。
select * from student as st, clazz as c;
select * from student st,clazz c;
-- from子句后,可以同时出现多个表。多个表会横向叠加到一起,而数据会形成一个笛卡尔积。
select * from student, clazz;
where 子句
从from获得的数据源中进行筛选。
ex:
--查询id小于10的记录
select * from student where id < 10;
- 整型1表示真,0表示假。
- 表达式由运算符和运算数组成。
- 运算数:变量(字段)、值、函数返回值
- 运算符:=, <=>, <>, !=, <=, <, >=, >, !, &&, ||, in (not) null, (not) like, (not) in, (not) between and, is (not), and, or, not, xor
is/is not (ture|false|unknown)
group by 子句, 分组子句
命令格式:group by 字段/别名 [排序方式]
分组后会进行排序。升序:asc,降序:desc
以下[合计函数]需配合 group by 使用:
count 返回不同的非NULL值数目 count(*)、count(字段)
sum 求和
max 求最大值
min 求最小值
avg 求平均值
group_concat 返回带有来自一个组的连接的非NULL值的字符串结果。组内字符串连接。
ex:
--统计所有用户的订单编号,各编号间用逗号分隔
select user_id, group_concat(order_id,',') from order group by user_id;
having 子句,条件子句
与 where 功能、用法相同,执行时机不同。
where 在开始时执行检测数据,对原数据进行过滤。
having 对筛选出的结果再次进行过滤。
having 字段必须是查询出来的,where 字段必须是数据表存在的。
where 不可以使用字段的别名,having 可以。因为执行where代码时,可能尚未确定列值。
where 不可以使用合计函数。一般需用合计函数才会用 having
SQL标准要求having必须引用group by子句中的列或用于合计函数中的列。
order by 子句,排序子句
order by 排序字段/别名 排序方式 [,排序字段/别名 排序方式]...
升序:asc,降序:desc
支持多个字段的排序。
limit 子句,限制结果数量子句
仅对处理好的结果进行数量限制。将处理好的结果的看作是一个集合,按照记录出现的顺序,索引从0开始。
limit 起始位置, 获取条数。
select * from student limit 10 ,10;
省略第一个参数,表示从索引0开始。
limit 获取条数
select * from student limit 10;
ps:limit和offset连用可用于分页
distinct, all 选项
distinct 去除重复记录
默认为 all, 全部记录
union
将多个select查询的结果组合成一个结果集合。
命令格式:select ... union[all | distinct] select ....
默认 distinct 方式,即所有返回的行都是唯一的,建议对每个select查询加上小括号包裹。order by 排序时,需加上 limit 进行结合。需要各select查询的字段数量一样。每个select查询的字段列表(数量、类型)应一致,因为结果中的字段名以第一条select语句为准。
ex:
select * from student union select * from student_temp;
from型
from后要求是一个表,必须给子查询结果取个别名。简化每个查询内的条件。from型需将结果生成一个临时表格,可用以原表的锁定的释放。子查询返回一个表,子查询需用括号包裹。表型子查询。
ex:
select from (select from student where id>0) as stu where id<10;
where型
子查询返回一个值,标量子查询。不需要给子查询取别名。
where子查询内的表,不能直接用以更新。
ex:
--取出订单表中消费金额最大的订单记录
select * from order where money = (select max(money) from order);
列子查询
如果子查询结果返回的是一列。使用 in 或 not in 完成查询。
exists 和 not exists 条件 如果子查询返回数据,则返回1或0。常用于判断条件。
ex:
select column1 from t1 where exists (select * from t2);
行子查询,查询条件是一个行。
ex:
select * from t1 where (id, gender) in (select id, gender from t2);
行构造符:(col1, col2, ...) 或 row(col1, col2, ...)行构造符通常用于与对能返回两个或两个以上列的子查询进行比较。
特殊运算符
!= all() 相当于 not in
= some() 相当于 in。any 是 some 的别名
!= some() 不等同于 not in,不等于其中某一个。
all, some 可以配合其他运算符一起使用。
连接查询(join)
将多个表的字段进行连接,可以指定连接条件。
连接方式|解释|例子
---|---|
内连接(inner join)|默认就是内连接,可省略inner。只有数据存在时才能发送连接。即连接结果不能出现空行。 on 表示连接条件。其条件表达式与where类似。也可以省略条件(表示条件永远为真) 也可用where表示连接条件。还有 using, 但需字段名相同。 using(字段名)|select * from student s join student_course sc on s.id=sc.student_id;
交叉连接 cross join|没有条件的内连接。|select * from tb1 cross join tb2;
外连接(outer join)|如果数据不存在,也会出现在连接结果中。|select * from student outer join student_course on student.id = student_course.student_id;
左外连接 left join|如果数据不存在,左表记录会出现,而右表为null填充|select * from student left join student_course on student.id = student_course.student_id;
右外连接 right join|如果数据不存在,右表记录会出现,而左表为null填充|select * from student right join student_course on student.id = student_course.student_id;
自然连接(natural join)|自动判断连接条件完成连接。相当于省略了using,会自动查找相同字段名。|select info.id, info.name, info.stu_num, extra_info.hobby, extra_info.sex from info, extra_info where info.stu_num = extra_info.stu_id;