执行顺序
from > where > group by > having > order by >limit
执行顺序高的语句要写在执行顺序低的语句前,否则会报错。
- 比如先写group by再写where就会报错
- having的作用是选择符合条件的组,也就是以组为单位筛选。
这种写法group by score having score = max/min(score)是错误的,因为having中的score不会遍历该分组,
此时的score与select scroe from XX group by scroe类似。
case when语法
case when 判断条件 then 处理 else 处理 end
--如果手机和桌面都使用,则为both,否则为手机或桌面
select
case when count(distinct platform) = 2 then 'both' else platform end
as platform from tb_users group by user_id;
连接查询
选择小表放右侧,作为驱动表,以提高性能
tb_college是小表,tb_student是大表
select tb_student.stu_name, tb_college.col_name from tb_student, tb_college
where tb_student.stu_id = tb_college.stu_id;
中文字段引号
mysql 8.0中, order by后面的字段如果加了引号,会导致order by失效
select stu_height as '身高' form tb_student order by '身高' desc; -- order by 失效
select stu_height as '身高' form tb_student order by 身高 desc; -- order by 有效
关于null
如果offset越界,整个select语句返回值是null, 而不是一张表
select stu_id from tb_student limit 100000, 1;
而再对null进行select, 返回一张表,表中字段是null, 等同于 select null;
select (select stu_id from tb_student limit 100000, 1);
如果指定一个字段,对null进行select,结果还是null, 而不是一张表
select sal from (select stu_id from tb_student limit 100000, 1);
关于空表
对空表的任何select,都将返回一个空表。注意空表并不是null。
因此,当tb是一张有price字段的空表,以下查询结果仍是空表:
select if(count(price) = 0, 0, price) from tb
想要返回price字段为0的表,可以使用union all
select 0 as price
union all
select price from tb
关于日期
日期格式,对天数加减不要使用+1 或-1,当日期为每月第一天和最后一天时,将不会进行跨月操作
使用date_add(XXX, interval 1 day) 或 date_sub(XXX, interval 1 day)来进行日期的加减.
select t2.date from t1, t2
where t2.date = date_add(t1.date, interval 1 day);
使用datediff(XXX, YYY)来进行XXX - YYY的运算.
select datediff(t2.date, t1.date) from t1, t2;
使用date_format(字段名,'%Y-%m-%D')来获得date类型的年、月、日
select date_format(date, '%Y-%m') as month from tb group by(date_format(date, '%Y-%m'));
小数位数
round(XXX, 小数位数) 四舍五入保留指定位数,当小数位数为负数,则开始保留整数位数
select round(t1.temperature, 2) from t1;
truncate(XXX, 小数位数) 在指定位数截断小数,舍去后面所有的位数
select truncate(t1.temperature, 2) from t1;
format(XXX, 小数位数) 四舍五入保留指定位数,位数不足用0补全,返回格式为字符串
select format(t1.temperature, 2) from t1;
性能
in/not in, distinct运算效率较低。可改为存在性判断替代集合运算和去重。
-- 查询所有主管的姓名和职位
select t1.ename, t1.job from tb_emp t1 where exists
(select 'x' from tb_emp t2 where t1.eno = t2.mgr);
----------------------------------------------------------------------
limit offset: 当offset 较大时,查询多个字段性能较差。可改为先查主键(带索引性能好),
再根据主键去查多列
select tb_emp.ename, tb_emp.job, tb_emp.sal from tb_emp
where tb_emp.eno = (select tb_emp.eno from tb_emp limit 1 offset 1000000000)
数据库设计
1NF:每个字段不能再进行差分。
- 一个表中,电话字段又分为固定电话和手机,则不满足1NF
2NF:非主键字段由全部主键才能决定。
- 主键(学号,学院号),字段 学院名称,则不满足2NF(因为学院号就能决定学院名称)
- 单主键的表,一般都满足2NF
3NF:非主键字段不能由其他非主键字段决定。
- 例:主键(学号),字段 学院号,学院名称,则不满足3NF
因为学号能决定学院号,而学院号能决定学院名称
BNF:有多种主键组合时,所有组合中的每个字段,都必须由其他所有字段才能决定。
- 主键(仓库号,货物号),属性 货物数量 仓库名,则不满足BNF
因为(仓库名, 货物号)也可以作为主键,而仓库名和仓库号可以相互决定。
不满足BNF及以下时,可能导致的问题
- 冗余性 减慢速度
- 更新异常 每次更新属性,需要更新所有记录,否则记录之间产生冲突
- 插入异常 因为冗余的字段不能为空
- 删除异常 会连带删除冗余的字段
PyMySql
cursor.execute(),括号中执行的sql语句只能有一个分号,否则执行失败。
原因是mysql服务器防止堆叠注入。
索引
创建复合索引
此复合索引能发挥索引性能的情况是:1. 按ename查询 2. 按ename,job查询
只查job时,此索引无法发挥作用,走index扫描。因为job在右侧
create index idx_emp on tb_emp (ename, job)
sum、avg、count、max、min窗口函数
如果over()中不写order by,那么窗口函数的对象是partition by生效后的所有记录。
如果over()中什么也不写,那么会返回所有行,每行都有相同的计算结果字段。(而如果不写over,只返回带有计算结果字段的一行)
count()可以附加条件,但一定要加else的情况。比如count(num = 2 or null), count(if(num=2, 1, null)),但要注意else的情况不能用0而要用null,否则会将所有的都计入
avg()也可以附加条件,比如select avg(tb_student.gender = 'male')*100 from tb_student; 求男性比例
sum()也可以附加条件,但要注意else的情况不能用null而要用0,否则结果可能出现null。比如select sum(if(status = 'OK', grade, 0)) from tb_grade;
散装函数
比较两个值
least(1, 2)
greatest(1, 2)