分页:
limit:
执行顺序:最后执行
好处:(减少每次返回数据量,提高查询效率,减少网络传输量,不用扫描全表,只要检索到对应数量的数据即可)
--limit格式: Limit 位置偏移量,条目数
--查询第一页数据
select * from employees limit 0,20;
--需求:每页显示pageSize条记录,此时显示第pageNo页:
--公式:Limit (pageNo-1) * pageSize,pageSize
offset:
--limit格式: Limit 位置偏移量,条目数
limit 4,3 从第四条开始取三条
--limit...offset...格式: Limit 条目数 offset 位置偏移量
limit 3 offset 4 取三条,从第四条开始
拓展:
多表查询(重点):
为什么需要多表查询(为什么要按业务水平划分表)?
- 多个表合在一起容易产生冗余字段
- 查询时,都查同一个表,影响查询效率
- 没有多表查询,分开提交多个SQL,请求多次,效率低
非等值连接:
自连接:
自己连接自己
外连接:
内连接是等值连接
七种 Join 的实现(面试重点):
会写这几种连接就差不多了
下图是oracle的实现方式,mysql只有inner join和左右连接,最下面的两个图需要配合union去实现
联合查询(union和union all):
可以把上面的七种查询互相加起来(拼图)
函数
单行函数:
数值函数
字符串函数
连接
mysql 大小写敏感吗
一、MySQL是大小写敏感的吗
MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。如果你稍加不注意就会出现在本机开发的程序运行一切正常,发布到服务器行就出现表名找不到的问题,一头雾水。
由于这个原因,在阿里巴巴规约中这样要求:
【强制】表名、字段名必须使用小写字母或数字 , 禁止出现数字开头,禁止两个下划线中间只 出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。
因此,数据库名、 表名、字段名,都不允许出现任何大写字母,避免引起不必要的麻烦。
二、MySQL的大小写敏感是由参数控制的
mysql大小写敏感配置相关的两个参数,lower_case_file_system 和 lower_case_table_names。
查看当前mysql的大小写敏感配置,可以使用如下语句
show global variables like '%lower_case%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| lower_case_file_system | ON |
| lower_case_table_names | 0 |
+------------------------+-------+
参数说明如下:
- lower_case_file_system,代表当前系统文件是否大小写敏感,只读参数,无法修改。ON 大小写不敏感,OFF 大小写敏感。
-
- 此变量描述数据所在的操作系统的文件目录是否区分大小写。 OFF表示文件名区分大小写,ON表示它们不区分大小写。此变量是只读的,因为它反映了文件系统的属性,设置它对文件系统没有影响。
- lower_case_table_names,代表表名是否大小写敏感,可以修改,参数有0、1、2三种。
-
- 0 大小写敏感。(Unix,Linux默认) 创建的库表将原样保存在磁盘上。如create database TeSt;将会创建一个TeSt的目录,create table AbCCC …将会原样生成AbCCC.frm文件,SQL语句也会原样解析。
- 1 大小写不敏感。(Windows默认) 创建的库表时,MySQL将所有的库表名转换成小写存储在磁盘上。 SQL语句同样会将库表名转换成小写。 如需要查询以前创建的Testtable(生成Testtable.frm文件),即便执行select * from Testtable,也会被转换成select * from testtable,致使报错表不存在。
- 2 大小写不敏感(OS X默认) 创建的库表将原样保存在磁盘上, 但SQL语句将库表名转换成小写。
三、MySQL大小写敏感如何设置
在Linux系统中修改my.cnf文件,在Windows下修改my.ini文件,新增或修改以下内容。
lower_case_table_names = 0 或 lower_case_table_names = 1
然后重启MySQL服务才可以生效。
四、开发注意事项
- 如果要将lower_case_table_names从0(敏感)修改为1(不敏感)时,必须先对旧数据表的表名进行处理,把所有数据库的表名先改为小写,最后再设置lower_case_table_names为1,否则依然会出现无法找到表名的问题。
- 在Windows上lower_case_table_names默认值为1(不敏感),在macOS上默认值为2(不敏感)。在Linux上不支持值2,服务器强制该值为0(敏感)。
- 并且MySQL官方也提示说:如果在数据目录驻留在不区分大小写的文件系统(例如Windows或macOS)上,则不应将lower_case_table_names设置为0。
- 否则将出现MySQL服务无法启动的问题。
五、总结
由于操作系统不同导致大小写敏感的默认设置不一致,我们在开发时一定要注意,应该养成严格的意识,SQL语句一律采用小写字母,避免无意义的踩坑。
日期和时间函数
获取日期、时间
日期与时间戳的转换
获取月份、星期、星期数、天数等函数
流程控制函数
Case。。。When。。。
聚合函数:
常用的聚合函数
AVG()
SUM()
MAX()
MIN()
COUNT()
详解:
AVG() 函数:
求平均值(要考虑空值的问题):
COUNT()函数:
COUNT(*)返回表中记录总数,适用于任意数据类型。
SELECT COUNT(*) FROM employees WHERE department_id = 50;
COUNT(expr字段名) 返回expr不为空的记录总数。
SELECT COUNT(commission_pct) FROM employees WHERE department_id = 50;
小结:
首先count是循环函数,一行一行去累加个数,每遍历一次就加一,类似累加器。
count(*)是有就累加。
count(1)是把遍历的格子用“1”去代替,然后进行累加,把1改成2结果也是一样,类似一个常数罢了。
count(列名)是把遍历的格子的非null值进行累加。
问题:用count(*) , count(1) , count(非空列名)谁好呢?
对于MyISAM引擎的表是没有区别的,都是O(1)。这种引擎内部有一计数器在维护着行数。
Innodb引擎的表用count(),count(1)直接读行数,复杂度是O(n),因为innodb真的要去数一遍。但好于具体的count(列名)。 三者效率:count() = count(1) > count(字段)
问题:能不能使用count(列名)替换count(*)?
不要使用 count(列名)来替代 count(*) , count(*) 是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。
GROUP BY 分组
先后顺序不影响实际结果
这一种写法是不对的,在select里的列除了聚合函数列之外,都要在group by里面,否则查出来的数据结果是错的,原因是job_id列会有多个,但是department_id组只有一个,导致数据错误(在oracle这样使用是会报错的)
总结:
1、SELECT 中出现的非聚合函数的字段必须声明在 GROUP BY 中。
反之,GROUP BY 中声明的字段可以不出现在SELECT中。
2、GROUP BY 声明在 FROM 和 WHERE 后面,ORDER BY 前面、LIMIT 前面。
3、MYSQL中GROUP BY 使用 WITH ROLLUP(汇总)时,不能同时使用 ORDER BY。
HAVING的使用(用来过滤数据的)
写在 GROUP BY 后面,用作过滤数据
SQL的执行原理(执行顺序)
执行顺序,1->2->3,123里面又从上到下,FROM关联多张表是笛卡尔积的ON先过滤等值连接完之后再使用JOIN去补充其他数据
启示:优化SQL语句的时候,把能够筛选掉最多数据的条件,放在优先级高的关键字去筛选。
详细:
SELECT 是先执行 FROM 这一步的。在这个阶段,如果是多张表联查,还会经历下面的几个步骤:
-
首先先通过 CROSS JOIN 求笛卡尔积,相当于得到虚拟表 vt(virtual table)1-1;
-
通过 ON 进行筛选,在虚拟表 vt1-1 的基础上进行筛选,得到虚拟表 vt1-2;
-
添加外部行。如果我们使用的是左连接、右链接或者全连接,就会涉及到外部行,也就是在虚拟表 vt1-2 的基础上增加外部行,得到虚拟表 vt1-3。 (补充数据)
当然如果我们操作的是两张以上的表,还会重复上面的步骤,直到所有表都被处理完为止。这个过程得到是我们的原始数据。
然后进入第三步和第四步,也就是 GROUP 和 HAVING 阶段 。在这个阶段中,实际上是在虚拟表 vt2 的基础上进行分组和分组过滤,得到中间的虚拟表 vt3 和 vt4 。
当我们完成了条件筛选部分之后,就可以筛选表中提取的字段,也就是进入到 SELECT 和 DISTINCT 阶段 。
首先在 SELECT 阶段会提取想要的字段,然后在 DISTINCT 阶段过滤掉重复的行,分别得到中间的虚拟表 vt5-1 和 vt5-2 。
当我们提取了想要的字段数据之后,就可以按照指定的字段进行排序,也就是 ORDER BY 阶段 ,得到虚拟表 vt6 。
最后在 vt6 的基础上,取出指定行的记录,也就是 LIMIT 阶段 ,得到最终的结果,对应的是虚拟表
vt7 。
当然我们在写 SELECT 语句的时候,不一定存在所有的关键字,相应的阶段就会省略。
同时因为 SQL 是一门类似英语的结构化查询语言,所以我们在写 SELECT 语句的时候,还要注意相应的关键字顺序,所谓底层运行的原理,就是我们刚才讲到的执行顺序。
子查询【嵌套查询】(重点)
子查询概念
子查询指一个查询语句嵌套在另一个查询语句内部的查询。
SQL 中子查询的使用大大增强了 SELECT 查询的能力,因为很多时候查询需要从结果集中获取数据,或者 需要从同一个表中先计算得出一个数据结果,然后与这个数据结果(可能是某个标量,也可能是某个集合)进行比较。
- 子查询(内查询)在主查询之前一次执行完成。
- 子查询的结果被主查询(外查询)使用 。
注意事项
-
- 子查询要包含在括号内
- 将子查询放在比较条件的右侧
- 单行操作符对应单行子查询,多行操作符对应多行子查询
子查询分类
角度1:从子查询返回的结果的条目数
单行子查询 和 多行子查询
角度2:子查询是否被执行多次
相关子查询 和 不相关子查询
相关子查询的需求:查询工资大于本部门平均工资的员工消息(员工的部门不一定都相同,所以子查询执行多次)
不相关子查询的需求:查询工资大于本公司平均工资的员工信息
单行子查询
单行比较操作符
单行子查询的操作符只能去匹配一个记录,否则会报错
多行子查询
多行比较操作符
相关子查询
如果子查询的执行依赖于外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询就称之为 关联子查询 。
相关子查询按照一行接一行的顺序执行,主查询的每一行都执行一次子查询。
执行流程
每次都进行一次子查询的执行(子查询执行多次)。
例子:
结论:
EXISTS 与 NOT EXISTS关键字(也是属于相关子查询)
关联子查询通常也会和 EXISTS操作符一起来使用,用来检查在子查询中是否存在满足条件的行。
如果在子查询中不存在满足条件的行:
条件返回 FALSE
继续在子查询中查找
如果在子查询中存在满足条件的行:
不在子查询中继续查找
条件返回 TRUE
NOT EXISTS关键字表示如果不存在某种条件,则返回TRUE,否则返回FALSE。
自连接、子查询 和 exist
题目:查询公司管理者的employee_id , last_name , job_id , department_id信息
方式一(exist):
exist中的SQL一般都是select * from的,然后
方式二(自连接):
方式三(子连接):