综合架构-DBA-03-SQL基础应用
SQL介绍
- 结构化查询语言,关系型数据库中通用的一类语言
- 5.7 以后符合SQL92严格模式
- 通过sql_mode参数来控制
常用SQL分类
MySQL客户端自带的功能
1 | mysql> help |
Server端分类命令
1 | mysql> help contents |
- DDL:数据定义语言
- DCL:数据控制语言
- DML:数据操作语言
- DQL:数据的查询语言
SQL的各种名词
sql_mode SQL模式
作用:规范SQL语句的书写方式,符合逻辑
1 | mysql> select @@sql_mode; |
数据类型
作用
保证数据的准确性和标准性。
种类
数值类型
说明:手机号是无法存储到int的。一般是使用char类型来存储收集号
字符类型
char(11) :
定长的字符串类型,在存储字符串时,最大字符长度11个,立即分配11个字符长度的存储空间,如果存不满,空格填充。
varchar(11):
变长的字符串类型看,最大字符长度11个。在存储字符串时,会先判断字符长度,按需分配存储空间。除了会存储字符串之外,还会额外使用1-2字节存储字符长度
以上两种数据类型选择需考虑周全,会影响到索引应用。括号中,设置的是字符的个数,无关字符类型。但是,不同种类的字符,占用的存储空间是不一样的,对于英文和数字,每个字符占1个字节长度,对于中文,占用空间大小要考虑字符集
enum(‘bj’,’js’,’sz’) 枚举类型
1 2 3 “下标索引”
枚举类型,比较适合于将来此列的值是固定范围内的特点,可以使用enum,可以很大程度的优化我们的索引结构。
时间类型
DATETIME(8个字节)
范围为从 1000-01-01 00:00:00.000000 至 9999-12-31 23:59:59.999999。
TIMESTAMP(4个字节)
1970-01-01 00:00:00.000000 至 2038-01-19 03:14:07.999999。
timestamp会受到时区的影响
二进制类型
json类型
列属性
列值不能为空,也是表设计的规范,尽可能将所有的列设置为非空。可以设置默认值为0
约束(一般建表时添加):
- primary key :主键约束
设置为主键的列,此列的值必须非空且唯一,主键在一个表中只能有一个,但是可以有多个列一起构成。 - not null :非空约束
列值不能为空,也是表设计的规范,尽可能将所有的列设置为非空。可以设置默认值为0 - unique key :唯一键
列值不能重复 - unsigned :无符号
针对数字列,非负数。
其他属性:
- key :索引
可以在某列上建立索引,来优化查询,一般是根据需要后添加 - default :默认值
列中,没有录入值时,会自动使用default的值填充 - auto_increment:自增长
针对数字列,顺序的自动填充数据(默认是从1开始,将来可以设定起始点和偏移量) - **comment ** : 注释
字符集和校对规则
字符集(charset)
查看当前mysql版本支持的字符集
1 | mysql> show charset; |
- utf8
- utf8mb4(支持的编码比utf8更多,如emoji),8.0+默认
校对规则(collation)
查看当前mysql版本支持的校对规则
1 | mysql> show collation; |
作用:影响到排序的操作,简单来说就是对大小写是否敏感
SQL应用
client
help|?:查看帮助
\c:结束上条命令运行,类似ctrl+c
\G:格式化输出
exit|\q:退出MySQL会话(ctrl+d)
source:导入SQL脚本,类似<
system:执行shell命令
server
DDL应用
数据定义语言
注意:在MySQL中,DDL语句在对表进行操作时,是要锁”元数据表”(类似于Linux的Inode信息)的。此时,所有修改类命令无法正常进行
所以:
- 在对于大表,业务繁忙的表,进行DDL操作时,要谨慎
- 尽量避开业务繁忙期
库定义
创建数据库
1 | create database school; |
建库规范:
1.库名不能有大写字母
2.建库要加字符集
3.库名不能有数字开头
4.库名要和业务相关
建库标准语句
1 | mysql> create database db charset utf8mb4; |
删除(生产中禁止使用)
1 | mysql> drop database kinmfer; |
修改
1 | SHOW CREATE DATABASE school; |
注意:修改字符集,修改后的字符集一定是原字符集的严格超集
查询库
1 | show databases; |
表定义
创建
1 | create table 库.表( |
1 | USE school; |
建表规范:
- 表名小写(多平台兼容性问题)
- 不能是数字开头
- 注意字符集和存储引擎
- 表名和业务有关
- 选择合适的数据类型
- 每个列都要有注释
- 列名不要太长
- 每个列设置为非空,无法保证非空,用0来填充。
- 不能使用关键字
- 必须要有主键
删除(生产中禁用命令)
1 | drop table t1; |
查询
1 | show tables; |
修改
在stu表中添加qq列
1 | DESC stu; |
在sname后加微信列
1 | ALTER TABLE stu ADD wechat VARCHAR(64) NOT NULL UNIQUE COMMENT '微信号' AFTER sname ; |
在id列前加一个新列num
1 | ALTER TABLE stu ADD num INT NOT NULL COMMENT '数字' FIRST; |
把刚才添加的列都删掉(危险)
1 | ALTER TABLE stu DROP num; |
修改sname数据类型的属性
1 | ALTER TABLE stu MODIFY sname VARCHAR(128) NOT NULL ; |
将sgender 改为 sg 数据类型改为 CHAR 类型
1 | ALTER TABLE stu CHANGE sgender sg CHAR(1) NOT NULL DEFAULT 'n' ; |
修改表名
1 | alter table ts01 rename to ts01_new; |
…
DCL应用
- grant
- revoke
DML应用
作用
对表中的数据行进行增、删、改
insert
1 | --- 最标准的insert语句 |
update
1 | DESC stu; |
delete(危险!!)
1 | DELETE FROM stu WHERE id=3; |
全表删除:
1 | DELETE FROM stu; |
常规办法:
都可以通过备份+日志恢复数据。
灵活办法:
delete可以通过反转日志(binlog),也可以通过延时从库进行恢复
伪删除:用update来替代delete,最终保证业务中查不到(select)即可
1 | 1.添加状态列 |
DQL应用(select )
获取表中的数据行
单独使用
1 | -- select @@xxx 查看系统参数 |
– select 函数();
1 | SELECT NOW(); |
https://dev.mysql.com/doc/refman/5.7/en/func-op-summary-ref.html?tdsourcetag=s_pcqq_aiomsg
select默认执行顺序
- from表1,表2
- where过滤条件1,过滤条件2
- group_by条件列1,条件列2
- having过滤条件1 过滤条件2
- order_by条件列1,条件列2
- limit限制
单表子句-from
1 | SELECT 列1,列2 FROM 表 |
例子:
– 查询stu中所有的数据(不要对大表进行操作)
1 | SELECT * FROM stu ; |
– 查询stu表中,学生姓名和入学时间
1 | SELECT sname,intime FROM stu; |
单表子句-where
1 | SELECT col1,col2 FROM TABLE WHERE colN 条件; |
where配合等值查询
例子:
– 查询中国(CHN)所有城市信息
1 | SELECT * FROM city WHERE countrycode='CHN'; |
– 查询北京市的信息
1 | SELECT * FROM city WHERE NAME='peking'; |
– 查询甘肃省所有城市信息
1 | SELECT * FROM city WHERE district='gansu'; |
where配合比较操作符(> < >= <= <>)
例子:
– 查询世界上少于100人的城市
1 | SELECT * FROM city WHERE population<100; |
where配合逻辑运算符(and or )
例子:
– 中国人口数量大于500w
1 | SELECT * FROM city WHERE countrycode='CHN' AND population>5000000; |
– 中国或美国城市信息
1 | SELECT * FROM city WHERE countrycode='CHN' OR countrycode='USA'; |
where配合模糊查询
例子:
– 查询省的名字前面带guang开头的
1 | SELECT * FROM city WHERE district LIKE 'guang%'; |
where配合in语句并且人口数量大于500w
– 中国或美国城市信息
1 | SELECT * FROM city WHERE countrycode IN('CHN','USA') AND population>5000000; |
where配合between and
例子:
– 查询世界上人口数量大于100w小于200w的城市信息
1 | SELECT * FROM city WHERE population >1000000 AND population <2000000; |
group by + 常用聚合函数
作用
根据 by后面的条件进行分组,方便统计,by后面跟一个列或多个列
常用聚合函数
1 | **max()** :最大值 |
例子1:统计世界上每个国家的总人口数.
1 | USE world |
例子2: 统计中国各个省的总人口数量
1 | SELECT district,SUM(Population) FROM city WHERE countrycode='chn' GROUP BY district; |
例子3:统计中国,每个省的总人口,城市个数,城市名列表
1 | select district,SUM(Population),count(id),name FROM city WHERE countrycode='chn' GROUP BY district; |
会报错!!!
说明:select list中的列,要么是group by的条件,要么就在聚合函数中出现
原理:MySQL不支持结果集是一对多行的显示方式
解决办法
1 | select district,SUM(Population),count(id),group_concat(name) FROM city WHERE countrycode='chn' GROUP BY district; |
having
作用:与where子句类型,having属于后过滤
1 | where|group|having |
例子4:统计中国每个省的总人口数,只打印总人口数小于100
1 | SELECT district,SUM(Population) |
order by + limit
作用
实现先排序,by后添加条件列
应用案例
查看中国所有的城市,并按人口数进行排序(从大到小)
1 | SELECT * FROM city WHERE countrycode='CHN' ORDER BY population DESC; |
统计中国各个省的总人口数量,按照总人口从大到小排序
1 | SELECT district AS 省 ,SUM(Population) AS 总人口 |
统计中国,每个省的总人口,找出总人口大于500w的,并按总人口从大到小排序,只显示前三名
1 | SELECT district, SUM(population) FROM city |
distinct:去重复
1 | SELECT countrycode FROM city ; |
联合查询- union all
1 | -- 中国或美国城市信息 |
join 多表连接查询
案例准备
按需求创建一下表结构:
1 | use school |
简单理解:多表连接实际上是将多张表中有关联的数据合并成一张表,在新表中再去做where group having order by limit
语法
笛卡尔乘积
1 | mysql> select * from teacher,course; |
内连接(最广泛)
A join B on A.xx=B.yy
1 | mysql> select * from teacher join course on teacher.tno=course.tno; |
外连接
left join:左表所有数据,右表满足条件的数据
right join:右表所有数据,左表满足条件的数据
驱动表是什么?
在多表连接当中,承当for循环中外层循环的角色。
此时,MySQL会拿着驱动表的每个满足条件的关联列的值,去依次找到for循环内循环中的关联值一一进行判断和匹配。
建议:将结果集小的表设置为驱动表更加合适。可以降低next loop的次数。
对于内连接来讲,我们是没法控制驱动表是谁,完全由优化器决定。
如果,需要人为干预,需要将内连接写成外连接的方式。left join可以强制左表为驱动表
查询张三的家庭住址
1 | SELECT A.name,B.address FROM |
例子:
查询一下世界上人口数量小于100人的城市名和国家名
1 | SELECT b.name ,a.name ,a.population |
查询城市shenyang,城市人口,所在国家名(name)及国土面积(SurfaceArea)
1 | SELECT a.name,a.population,b.name ,b.SurfaceArea |
别名
1 | 列别名,表别名 |
多表SQL练习题
统计zhang3,学习了几门课
1 | SELECT st.sname , COUNT(sc.cno) |
查询zhang3,学习的课程名称有哪些?
1 | SELECT st.sname , GROUP_CONCAT(co.cname) |
查询oldguo老师教的学生名.
1 | SELECT te.tname ,GROUP_CONCAT(st.sname) |
查询oldguo所教课程的平均分数
1 | SELECT te.tname,AVG(sc.score) |
每位老师所教课程的平均分,并按平均分排序
1 | SELECT te.tname,AVG(sc.score) |
查询oldguo所教的不及格的学生姓名
1 | SELECT te.tname,st.sname,sc.score |
查询所有老师所教学生不及格的信息
1 | SELECT te.tname,st.sname,sc.score |
case when 判断 then 结果 end
1 | mysql> select concat(teacher .tname, "_",teacher.tno) ,concat(count(case when score.score>60 then 1 end)/count(score.sno)*100,"%") as 及格率 |
information_schema.tables视图
1 | DESC information_schema.TABLES |
查询整个数据库中所有库和所对应的表信息
1 | SELECT table_schema,GROUP_CONCAT(table_name) |
统计所有库下的表个数
1 | SELECT table_schema,COUNT(table_name) |
查询所有innodb引擎的表及所在的库
1 | SELECT table_schema,table_name,ENGINE FROM information_schema.`TABLES` |
统计world数据库下每张表的磁盘空间占用
1 | SELECT table_name,CONCAT((TABLE_ROWS*AVG_ROW_LENGTH+INDEX_LENGTH)/1024," KB") AS size_KB |
统计所有数据库的总的磁盘空间占用
1 | SELECT |
生成整个数据库下的所有表的单独备份语句
1 | 模板语句: |
107张表,都需要执行以下2条语句
1 | ALTER TABLE world.city DISCARD TABLESPACE; |
查询业务数据库(系统库除外),所有非InnoDB表。将非InnoDB表转化为InnoDB
1 | select concat("alter table ",table_schema,".",table_name," engine=innodb;" ) |
但是要在my.cnf中加入
1 | [mysqld] |
show 命令
1 | show databases; #查看所有数据库 |