MySQL思维导图
2021-06-29 22:07:07 0 举报
Mysql思维导图
作者其他创作
大纲/内容
表于表之间的关系
外键
一对多关系
foreign key<br> 1 一对多表关系 外键字段建在多的一方<br> 2 在创建表的时候 一定要先建被关联表 <br> 3 在录入数据的时候 也必须先录入被关联表
# SQL语句建立表关系<br>create table dep(<br> id int primary key auto_increment,<br> dep_name char(16),<br> dep_desc char(32)<br>);<br><br>create table emp(<br> id int primary key auto_increment,<br> name char(16),<br> gender enum('male','female','others') default 'male',<br> dep_id int,<br> foreign key(dep_id) references dep(id)<br>);<br>insert into dep(dep_name,dep_desc) values('sb教学部','教书育人'),('外交部','多人外交'),('nb技术部','技术能力有限部门');<br>insert into emp(name,dep_id) values('jason',2),('egon',1),('tank',1),('kevin',3);
级联更新、级联删除
# 修改dep表里面的id字段<br>update dep set id=200 where id=2; 不行<br># 删除dep表里面的数据<br>delete from dep; 不行
# 1 先删除教学部对应的员工数据 之后再删除部门<br> 操作太过繁琐<br> <br># 2 真正做到数据之间有关系<br> 更新就同步更新<br> 删除就同步删除
"""<br>级联更新 >>> 同步更新<br>级联删除 >>> 同步删除<br>"""<br>create table dep(<br> id int primary key auto_increment,<br> dep_name char(16),<br> dep_desc char(32)<br>);<br><br>create table emp(<br> id int primary key auto_increment,<br> name char(16),<br> gender enum('male','female','others') default 'male',<br> dep_id int,<br> foreign key(dep_id) references dep(id) <br> on update cascade # 同步更新<br> on delete cascade # 同步删除<br>);<br>insert into dep(dep_name,dep_desc) values('sb教学部','教书育人'),('外交部','多人外交'),('nb技术部','技术能力有限部门');<br>insert into emp(name,dep_id) values('jason',2),('egon',1),('tank',1),('kevin',3);
多对多关系
图书表和作者表<br>其实我们只是想记录书籍和作者的关系<br>针对多对多字段表关系 不能在两张原有的表中创建外键<br>需要你单独再开设一张 专门用来存储两张表数据之间的关系<br><br>create table book(<br> id int primary key auto_increment,<br> title varchar(32),<br> price int<br>);<br>create table author(<br> id int primary key auto_increment,<br> name varchar(32),<br> age int<br>);<br>create table book2author(<br> id int primary key auto_increment,<br> author_id int,<br> book_id int,<br> foreign key(author_id) references author(id) <br> on update cascade # 同步更新<br> on delete cascade, # 同步删除<br> foreign key(book_id) references book(id) <br> on update cascade # 同步更新<br> on delete cascade # 同步删除<br>);
一对一
一对一 外键字段建在任意一方都可以 但是推荐你建在查询频率比较高的表中<br>create table authordetail(<br> id int primary key auto_increment,<br> phone int,<br> addr varchar(64)<br>);<br>create table author(<br> id int primary key auto_increment,<br> name varchar(32),<br> age int,<br> authordetail_id int unique,<br> foreign key(authordetail_id) references authordetail(id) <br> on update cascade # 同步更新<br> on delete cascade # 同步删除<br>)
修改表
# MySQL对大小写是不敏感的<br>"""<br>1 修改表名<br> alter table 表名 rename 新表名;<br><br>2 增加字段<br> alter table 表名 add 字段名 字段类型(宽度) 约束条件;<br> alter table 表名 add 字段名 字段类型(宽度) 约束条件 first;<br> alter table 表名 add 字段名 字段类型(宽度) 约束条件 after 字段名;<br><br>3 删除字段<br> alter table 表名 drop 字段名;<br><br>4 修改字段<br> alter table 表名 modify 字段名 字段类型(宽度) 约束条件;<br> <br> alter table 表名 change 旧字段名 新字段名 字段类型(宽度) 约束条件;<br> <br>"""
复制表
"""<br>我们sql语句查询的结果其实也是一张虚拟表<br>"""<br>create table 表名 select * from 旧表; 不能复制主键 外键 ...<br><br>create table new_dep2 select * from dep where id>3;
表查询
前期表准备
create table emp(<br> id int not null unique auto_increment,<br> name varchar(20) not null,<br> sex enum('male','female') not null default 'male', #大部分是男的<br> age int(3) unsigned not null default 28,<br> hire_date date not null,<br> post varchar(50),<br> post_comment varchar(100),<br> salary double(15,2),<br> office int, #一个部门一个屋子<br> depart_id int<br>);<br><br>#插入记录<br>#三个部门:教学,销售,运营<br>insert into emp(name,sex,age,hire_date,post,salary,office,depart_id) values<br>('jason','male',18,'20170301','张江第一帅形象代言',7300.33,401,1), #以下是教学部<br>('tom','male',78,'20150302','teacher',1000000.31,401,1),<br>('kevin','male',81,'20130305','teacher',8300,401,1),<br>('tony','male',73,'20140701','teacher',3500,401,1),<br>('owen','male',28,'20121101','teacher',2100,401,1),<br>('jack','female',18,'20110211','teacher',9000,401,1),<br>('jenny','male',18,'19000301','teacher',30000,401,1),<br>('sank','male',48,'20101111','teacher',10000,401,1),<br>('哈哈','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门<br>('呵呵','female',38,'20101101','sale',2000.35,402,2),<br>('西西','female',18,'20110312','sale',1000.37,402,2),<br>('乐乐','female',18,'20160513','sale',3000.29,402,2),<br>('拉拉','female',28,'20170127','sale',4000.33,402,2),<br>('僧龙','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门<br>('程咬金','male',18,'19970312','operation',20000,403,3),<br>('程咬银','female',18,'20130311','operation',19000,403,3),<br>('程咬铜','male',18,'20150411','operation',18000,403,3),<br>('程咬铁','female',18,'20140512','operation',17000,403,3);<br><br><br># 当表字段特别多 展示的时候错乱 可以使用\G分行展示<br>select * from emp\G;<br><br># 个别同学的电脑在插入中文的时候还是会出现乱码或者空白的现象 你可以将字符编码统一设置成GBK
# 书写顺序<br>select id,name from emp where id > 3;<br># 执行顺序<br>from<br>where<br>select<br><br>"""<br>虽然执行顺序和书写顺序不一致 你在写sql语句的时候可能不知道怎么写<br>你就按照书写顺序的方式写sql<br> select * 先用*号占位<br> 之后去补全后面的sql语句<br> 最后将*号替换后你想要的具体字段<br> <br> 明天会一直使用 这里先理解<br>"""
where筛选条件
# 作用:是对整体数据的一个筛选操作<br># 1.查询id大于等于3小于等于6的数据<br>select id,name,age from emp where id>=3 and id<=6;<br>select id,name from emp where id between 3 and 6; 两者等价<br><br># 2.查询薪资是20000或者18000或者17000的数据<br>select * from emp where salary=20000 or salary=18000 or salary=17000;<br>select * from emp where salary in (20000,18000,17000);<br><br># 3.查询员工姓名中包含字母o的员工的姓名和薪资<br>"""<br>模糊查询<br> like<br> % 匹配任意多个字符<br> _ 匹配任意单个字符<br>"""<br>select name,salary from emp where name like '%o%';<br><br># 4.查询员工姓名是由四个字符组成的 姓名和薪资 char_length() _<br>select name,salary from emp where name like '____';<br>select name,salary from emp where char_length(name) = 4;<br><br># 5.查询id小于3或者id大于6的数据<br>select * from emp where id not between 3 and 6;<br><br># 6.查询薪资不在20000,18000,17000范围的数据<br>select * from emp where salary not in (20000,18000,17000);<br><br># 7.查询岗位描述为空的员工姓名和岗位名 针对null不用等号 用is<br>select name,post from emp where post_comment = NULL;<br>select name,post from emp where post_comment is NULL;
group by分组
# 分组实际应用场景 分组应用场景非常的多<br> 男女比例<br> 部门平均薪资<br> 部门秃头率<br> 国家之间数据统计<br><br># 1 按照部门分组<br>select * from emp group by post;<br>"""<br>分组之后 最小可操作单位应该是组 还不再是组内的单个数据<br> 上述命令在你没有设置严格模式的时候是可正常执行的 返回的是分组之后 每个组的第一条数据 但是这不符合分组的规范:分组之后不应该考虑单个数据 而应该以组为操作单位(分组之后 没办法直接获取组内单个数据)<br> 如果设置了严格模式 那么上述命令会直接报错 <br>"""<br>set global sql_mode = 'strict_trans_tables,only_full_group_by';<br><br>设置严格模式之后 分组 默认只能拿到分组的依据<br>select post from emp group by post; <br>按照什么分组就只能拿到分组 其他字段不能直接获取 需要借助于一些方法(聚合函数)<br><br><br>"""<br>什么时候需要分组啊???<br> 关键字 <br> 每个 平均 最高 最低 <br> <br> 聚合函数<br> max<br> min<br> sum<br> count<br> avg<br>"""<br># 1.获取每个部门的最高薪资<br>select post,max(salary) from emp group by post;<br>select post as '部门',max(salary) as '最高薪资' from emp group by post;<br>select post '部门',max(salary) '最高薪资' from emp group by post;<br># as可以给字段起别名 也可以直接省略不写 但是不推荐 因为省略的话语意不明确 容易错乱<br><br># 2.获取每个部门的最低薪资<br>select post,min(salary) from emp group by post;<br># 3.获取每个部门的平均薪资<br>select post,avg(salary) from emp group by post;<br># 4.获取每个部门的工资总和<br>select post,sum(salary) from emp group by post;<br># 5.获取每个部门的人数<br>select post,count(id) from emp group by post; # 常用 符合逻辑<br>select post,count(salary) from emp group by post;<br>select post,count(age) from emp group by post;<br>select post,count(post_comment) from emp group by post; null不行<br><br># 6.查询分组之后的部门名称和每个部门下所有的员工姓名 <br># group_concat不单单可以支持你获取分组之后的其他字段值 还支持拼接操作<br>select post,group_concat(name) from emp group by post;<br>select post,group_concat(name,'_DSB') from emp group by post;<br>select post,group_concat(name,':',salary) from emp group by post;<br># concat不分组的时候用 <br>select concat('NAME:',name),concat('SAL:',salary) from emp;<br><br># 补充 as语法不单单可以给字段起别名 还可以给表临时起别名<br>select emp.id,emp.name from emp; <br>select emp.id,emp.name from emp as t1; 报错<br>select t1.id,t1.name from emp as t1;<br><br># 查询每个人的年薪 12薪<br>select name,salary*12 from emp;
分组注意事项
# 关键字where和group by同时出现的时候group by必须在where的后面<br>where先对整体数据进行过滤之后再分组操作<br>where筛选条件不能使用聚合函数<br>select id,name,age from emp where max(salary) > 3000;<br><br>select max(salary) from emp; # 不分组 默认整体就是一组<br><br># 统计各部门年龄在30岁以上的员工平均薪资<br> 1 先求所有年龄大于30岁的员工<br> select * from emp where age>30;<br> 2 再对结果进行分组<br> select * from emp where age>30 group by post;<br> <br> select post,avg(salary) from emp where age>30 group by post;
having分组之后的筛选条件
"""<br>having的语法根where是一致的<br>只不过having是在分组之后进行的过滤操作<br>即having是可以直接使用聚合函数的<br>"""<br># 统计各部门年龄在30岁以上的员工平均工资并且保留平均薪资大于10000的部门<br>select post,avg(salary) from emp <br> where age>30 <br> group by post<br> having avg(salary) > 10000<br> ;
distinct去重
"""<br>一定要注意 必须是完全一样的数据才可以去重!!!<br>一定不要将主键忽视了 有主键存在的情况下 是不可能去重的<br>[<br>{'id':1,'name':'jason','age':18},<br>{'id':2,'name':'jason','age':18},<br>{'id':3,'name':'egon','age':18}<br>]<br>ORM 对象关系映射 让不懂SQL语句的人也能够非常牛逼的操作数据库<br>表 类<br>一条条的数据 对象<br>字段对应的值 对象的属性<br><br>你再写类 就意味着在创建表<br>用类生成对象 就意味着再创建数据<br>对象点属性 就是在获取数据字段对应的值<br>目的就是减轻python程序员的压力 只需要会python面向对象的知识点就可以操作MySQL<br>"""<br>select distinct id,age from emp;<br>select distinct age from emp;
order排序
select * from emp order by salary;<br>select * from emp order by salary asc;<br>select * from emp order by salary desc;<br>"""<br>order by默认是升序 asc 该asc可以省略不写<br>也可以修改为降序 desc<br>"""<br>select * from emp order by age desc,salary asc;<br># 先按照age降序排 如果碰到age相同 则再按照salary升序排<br><br># 统计各部门年龄在10岁以上的员工平均工资并且保留平均薪资大于1000的部门,然后对平均工资降序排序<br> select post,avg(salary) from emp <br> where age>10 <br> group by post<br> having avg(salary) > 1000<br> order by avg(salary) desc<br> ;
limit限制展示条数
select * from emp;<br>"""针对数据过多的情况 我们通常都是做分页处理"""<br>select * from emp limit 3; # 只展示三条数据<br><br>select * from emp limit 0,5;<br>select * from emp limit 5,5;<br>第一个参数是起始位置<br>第二个参数是展示条数
正则
mysql也支持正则
select * from emp where name regexp '^j.*(n|y)$';
多表操作
前期表准备
#建表<br>create table dep(<br>id int,<br>name varchar(20) <br>);<br><br>create table emp(<br>id int primary key auto_increment,<br>name varchar(20),<br>sex enum('male','female') not null default 'male',<br>age int,<br>dep_id int<br>);<br><br>#插入数据<br>insert into dep values<br>(200,'技术'),<br>(201,'人力资源'),<br>(202,'销售'),<br>(203,'运营');<br><br>insert into emp(name,sex,age,dep_id) values<br>('jason','male',18,200),<br>('egon','female',48,201),<br>('kevin','male',18,201),<br>('nick','male',28,202),<br>('owen','male',18,203),<br>('jerry','female',18,204);
多表查询
select * from dep,emp; # 结果 笛卡尔积<br>"""<br>了解即可 不知道也没关系<br>"""<br><br>select * from emp,dep where emp.dep_id = dep.id;<br><br>"""<br>MySQL也知道 你在后面查询数据过程中 肯定会经常用到拼表操作 <br>所以特地给你开设了对应的方法<br> inner join 内连接<br> left join 左连接<br> right join 右连接<br> union 全连接<br>"""<br># inner join 内连接<br>select * from emp inner join dep on emp.dep_id = dep.id;<br># 只拼接两张表中公有的数据部分<br><br># left join 左连接<br>select * from emp left join dep on emp.dep_id = dep.id;<br># 左表所有的数据都展示出来 没有对应的项就用NULL<br><br># right join 右连接<br>select * from emp right join dep on emp.dep_id = dep.id;<br># 右表所有的数据都展示出来 没有对应的项就用NULL<br><br># union 全连接 左右两表所有的数据都展示出来<br>select * from emp left join dep on emp.dep_id = dep.id<br>union<br>select * from emp right join dep on emp.dep_id = dep.id;
子查询
"""<br>子查询就是我们平时解决问题的思路<br> 分步骤解决问题<br> 第一步<br> 第二步<br> ...<br>将一个查询语句的结果当做另外一个查询语句的条件去用<br>"""<br># 查询部门是技术或者人力资源的员工信息<br> 1 先获取部门的id号<br> 2 再去员工表里面筛选出对应的员工<br> select id from dep where name='技术' or name = '人力资源';<br> <br> select name from emp where dep_id in (200,201);<br> <br> <br> select * from emp where dep_id in (select id from dep where name='技术' or name = '人力资源');
总结
表的查询结果可以作为其他表的查询条件<br>也可以通过起别名的方式把它作为一个张虚拟表根其他表关联<br><br>"""<br>多表查询就两种方式<br> 先拼接表再查询<br> 子查询 一步一步来<br>"""
navicat软件
练习题
"""<br>课下一定要把握上课将的这几道题全部自己独立的理解并写出来<br><br>在解决sql查询问题的时候 不要慌<br>一步一步慢慢来 最终能够东拼西凑出来就过关了!!!<br><br>"""<br>-- 1、查询所有的课程的名称以及对应的任课老师姓名<br>-- SELECT<br>-- course.cname,<br>-- teacher.tname <br>-- FROM<br>-- course<br>-- INNER JOIN teacher ON course.teacher_id = teacher.tid;<br><br>-- 4、查询平均成绩大于八十分的同学的姓名和平均成绩<br>-- SELECT<br>-- student.sname,<br>-- t1.avg_num <br>-- FROM<br>-- student<br>-- INNER JOIN (<br>-- SELECT<br>-- score.student_id,<br>-- avg( num ) AS avg_num <br>-- FROM<br>-- score<br>-- INNER JOIN student ON score.student_id = student.sid <br>-- GROUP BY<br>-- score.student_id <br>-- HAVING<br>-- AVG( num ) > 80 <br>-- ) AS t1 ON student.sid = t1.student_id;<br><br><br>-- 7、 查询没有报李平老师课的学生姓名<br># 分步操作<br># 1 先找到李平老师教授的课程id<br># 2 再找所有报了李平老师课程的学生id<br># 3 之后去学生表里面取反 就可以获取到没有报李平老师课程的学生姓名<br>-- SELECT<br>-- student.sname <br>-- FROM<br>-- student <br>-- WHERE<br>-- sid NOT IN (<br>-- SELECT DISTINCT<br>-- score.student_id <br>-- FROM<br>-- score <br>-- WHERE<br>-- score.course_id IN ( SELECT course.cid FROM teacher INNER JOIN course ON teacher.tid = course.teacher_id WHERE teacher.tname = '李平老师' ) <br>-- );<br><br>-- 8、 查询没有同时选修物理课程和体育课程的学生姓名<br>-- (只要选了一门的 选了两门和没有选的都不要)<br># 1 先查物理和体育课程的id<br># 2 再去获取所有选了物理和体育的学生数据<br># 3 按照学生分组 利用聚合函数count筛选出只选了一门的学生id<br># 4 依旧id获取学生姓名<br>-- SELECT<br>-- student.sname <br>-- FROM<br>-- student <br>-- WHERE<br>-- student.sid IN (<br>-- SELECT<br>-- score.student_id <br>-- FROM<br>-- score <br>-- WHERE<br>-- score.course_id IN ( SELECT course.cid FROM course WHERE course.cname IN ( '物理', '体育' ) ) <br>-- GROUP BY<br>-- score.student_id <br>-- HAVING<br>-- COUNT( score.course_id ) = 1 <br>-- );<br><br>-- 9、 查询挂科超过两门(包括两门)的学生姓名和班级<br># 1 先筛选出所有分数小于60的数据<br># 2 按照学生分组 对数据进行计数获取大于等于2的数据<br>SELECT<br> class.caption,<br> student.sname <br>FROM<br> class<br> INNER JOIN student ON class.cid = student.class_id <br>WHERE<br> student.sid IN (<br> SELECT<br> score.student_id <br> FROM<br> score <br> WHERE<br> score.num < 60 GROUP BY score.student_id HAVING COUNT( score.course_id ) >= 2 <br> );
sql注入
"""<br>利用一些语法的特性 书写一些特点的语句实现固定的语法<br>MySQL利用的是MySQL的注释语法<br>select * from user where name='jason' -- jhsadklsajdkla' and password=''<br><br>select * from user where name='xxx' or 1=1 -- sakjdkljakldjasl' and password=''<br>"""<br>日常生活中很多软件在注册的时候都不能含有特殊符号<br>因为怕你构造出特定的语句入侵数据库 不安全<br><br># 敏感的数据不要自己做拼接 交给execute帮你拼接即可<br># 结合数据库完成一个用户的登录功能?<br>import pymysql<br><br><br>conn = pymysql.connect(<br> host = '127.0.0.1',<br> port = 3306,<br> user = 'root',<br> password = '123456',<br> database = 'day48',<br> charset = 'utf8' # 编码千万不要加-<br>) # 链接数据库<br>cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)<br><br>username = input('>>>:')<br>password = input('>>>:')<br>sql = "select * from user where name=%s and password=%s"<br># 不要手动拼接数据 先用%s占位 之后将需要拼接的数据直接交给execute方法即可<br>print(sql)<br>rows = cursor.execute(sql,(username,password)) # 自动识别sql里面的%s用后面元组里面的数据替换<br>if rows:<br> print('登录成功')<br> print(cursor.fetchall())<br>else:<br> print('用户名密码错误')
数据库介绍<br>
数据库的本质:本质其实就是一款基于网络通信的应用程序<br>
关系型数据库
1. 数据之间彼此有关系或约束
2. 存储数据的变现形式通常是以表格存储
非关系性数据库
存储数据通常是以k,v键值对的形式
MySQL的安装
网站:www.mysql.com
目录结构
客户端:bin目录下的mysql.exe
服务端:bin目录下的mysqld.exe
启动
以管理员身份运行,因为部分命令仅管理员身份有效
服务端:先切换到mysqld所在目录下,然后输入mysqld即可启动服务端
客户端:保留原来窗口,重新打开cmd窗口客户端链接服务端完整命令:
mysql -h 127.0.0.1 -P 3306 -uroot -p
环境变量配置
将bin目录添加到环境变量中
将mysql服务端制作成系统服务(开机自启)
安装mysql服务:mysqld --install
卸载mysql服务:mysqld --remove
统一编码配置
my-default.ini 文件是默认配置模板,程序启动会先夹在配置文件中的配置之后才真正的启动
[mysqld] # 一旦服务端启动立刻加载这下面的配置<br>[mysql] # 一旦客户端启动立刻加载这下面的配置<br>[client] # 其他客户端<br>
新建一个my.ini配置文件,然后添加配置,修改配置文件后一定要重启服务才能生效
[mysqld]<br>character-set-server=utf8<br>collation-server=utf8_general_ci<br>[client]<br>default-character-set=utf8<br>[mysql]<br>user="root" # 此是直接将用户名密码添加到配置文件中,使启动mysql时候,直接以root账号登录<br>password=123456<br>default-character-set=utf8
SQL语句初识
1. MySQl中的sql语句是以分号作为结束的标志
2. 基本命令
查看所有库名:show databases;
3. 连接服务的的命令简写:mysql -uroot -p(默认本地,默认端口形式连接)
4. 当你输入的命令不对,又不想让服务端执行并返回错误信息是,可以用 /c 来取消
5. 客户端退出:退出命令加不加分好都可以执行
quit
exit
6. 当你在连接服务端的时候,只输入mysql也能链接,但此时不是管理员身份,而是一个游客身份
7. 设置密码:
mysqladmin -uroot -p原密码 password 新密码
示例:mysqladmin -uroot -p123 password 123456
8. 重置密码:
1. 先关闭当前mysql服务端;然后以命令行方式启动服务端(让mysql跳过用户名密码验证功能)
mysqld --skip-grant-tables
2. 以无密码方式连接
mysql -uroot -p 直接回车
3. 修改当前用户的密码:
update mysql.user set password=password(123456) where user='root' and host='localhost';
4. 立刻将修改数据刷到硬盘
flush privileges;
5. 关闭当前服务端,然后以正常校验授权表的形式启动
针对库的增删改查(文件夹)
增
create database db1;
新增库,并制定编码格式:<br>cerate database db2 charset='gbk';
查
查所有库:<br>show databases;
查单个库,且查询的是创建库的语句:<br>show create database db1;
改
alter database db2 charset='utf8';
删
drop database db2;
<span style="font-size: inherit;">针对表的增删改查(文件)</span><br>
在操作表(文件)的时候,需要指定所在的库(文件夹)
查看当前所在库的名字
select database();
切换库
use db1;
也可以用绝对路径的形式操作不同的库
create table db2.t1(id int);
增
create tabale t1(id int,name char(4));
查
查看当前库下所有的表名:<br>show tables;
查看某个表的创建语句:<br>show create table t1;
查看表结构:<br>describe t1;<br>简写:desc t1;
改
alter table t1 modify name char(16);
删
drop table t1;
针对数据的增删改查(一行行数据)
一定要先有库,有表,才能操作记录
增
插入一条数据:<br>inster into t1 value(1,'jason');
插入多条数据:<br>inster into t1 value(1,'jason'),(2,'egon'),(3,'tank');
查
当数据量特别大的时候,不建议使用该命令<br>select * from t1;
查询该表中,所有的name字段<br>select name from t1;
改
update t1 set name='dsb' where id > 1;
删
delete from t1 where id > 1;
delete from t1 where name='jason';
将表所有的数据清空
delete from t1;
存储引擎
介绍
innodb
是MySQL5.5版本及之后默认的存储引擎<br>数据存储更加安全
myisam
是MySQL5.5版本之前默认的存储引擎<br>速度要比innodb快,但是我们更加注重的是数据的安全
memory
内存引擎(数据全部存放在内存中)断电数据丢失
blackhole
无论什么时候,都立刻消失(黑洞)
使用
查看所有的存储引擎
show engines;
不同的存储引擎在存储表的时候,异同点
create table t1(id int) engine=innodb;
create table t2(id int) engine=myisam;
create table t3(id int) engine=blackhole;
create table t4(id int) engine=memory;
基本数据类型
创建表的完整语法
语法
create table 表名(<br> 字段名1 类型(宽度) 约束条件,<br> 字段名2 类型(宽度) 约束条件,<br> 字段名3 类型(宽度) 约束条件<br>)
注意
1. 同一张表中字段名不能重复
2. 宽度和约束条件是可选的(可写可不写)而字段名和<br>字段类型是必须的约束条件写的话,也支持写多个<br>
字段名1 类型(宽度) 约束条件1 约束条件2...,<br> create table t5(id); 报错
3. 最后一行不能有逗号
create table t6(<br> id int,<br> name char,<br> ); 报错
补充
宽度
一般情况下指的是对存储数据的限制
create table t7(name char); # 默认宽度是1<br> insert into t7 values('jason'); # 会自动截取<br> insert into t7 values(null); # 会存关键字NULL
5.6版本默认没有开启严格模式,规定只能存一个字符,<br>你给了多个字符,那么MySQL会自动帮你截取
5.7版本及以上或者开启了严格模式,那么规定只能存几个,就不能超,<br>一旦超出范围,会立刻报错 Data too long for ...
严格模式到底开不开呢?
5.7以后的版本默认都是开启严格模式的
使用数据库的准则:<br>能尽量少的让数据库干活就尽量少,不要给数据库增加额外的压力
约束条件 null not null 不能插入null
create table t8(id int,name char not null);
总结:<br>宽度和约束条件到底是什么关系
宽度是用来限制数据的存储<br>约束条件是在宽度的基础之上增加的额外的约束
严格模式
查看严格模式
show variables like '%mode';
'%mode'<br>模糊匹配/查询<br> %:匹配任意多个字符<br> _:匹配任意单个字符
修改严格模式
set session # 只在当前窗口有效<br>set global # 全局有效<br><br>set global sql_mode = 'STRICT_TRANS_TABLES';<br>修改完之后,冲新进入服务端即可
修改sql_mode,让M有SQL不要做自动剔除空格操作<br>set global sql_mode = 'STRICT_TRANS_TABLES,PAD_CHAR_TO_FULL_LENGTH';
整型
分类<br>tinyint smallint meduimnt int bigint
作用:<br>存储年龄、等级、id、号码等
以tinyint为例
是否有符号<br>默认情况下是带符号的
超出会如何:<br>超出限制只存最大可接受值
create table t9(id tinyint);<br>insert into t9 values(-129),(256);
约束条件之unsigned。无符号
create table t10(id tinyint unsigned);
int 也是默认带符号的,整型默认情况下都是带有符号的
只有整形括号里面的数字不是表示限制位数<br>id int(8)<br> 如果数字没有超出8位,那么默认用空格填充至8位<br> 如果数字超出了8位,那么有几位就存几位(但是还是要遵守最大范围)<br>create table t13(id int(8) unsigned zerofill); # 用0填充至8位<br>针对整型字段,括号内无需指定宽度,因为它默认的宽度(11位)足够显示<br>所有的数据了
浮点型
分类:<br>FLOAT DOUBLE DECIMAL
作用:<br>身高、体重、薪资
存储限制:<br>float(255,30) # 总共255位 小数部分占30位<br>double(255,30) # 总共255位 小数部分占30位<br>decimal(65,30) # 总共65位 小数部分占30位<br>
精确度验证:<br>create table t15(id float(255,30));<br>create table t16(id double(255,30));<br>create table t17(id decimal(65,30));<br>
float < double < decimal<br># 要结合实际应用场景 三者都能使用
字符类型
char<br> 定长<br> char(4) 数据超过4个字符直接报错,不够4个字符空格不全<br><br>varchar<br> 变长<br> varchar(4) 数据超过4个字符直接报错,不够有几个存几个
create table t18(name char(4));<br>create table t19(name varchar(4));<br>
char_length统计字段长度<br>
select char_length(name) form t18;
char与varchar对比
char<br> 缺点:浪费空间<br> 优点:存取都很简单<br> 直接按照固定字符存储数据即可<br> 存按照5个字符存,取也直接按照5个字符取,速度就会相对varchar快
varchar<br> 优点:节省空间<br> 缺点:存取较为麻烦<br> 存的时候需要制作报头<br> 取的时候也要先读取报头,之后才能读取真实数据
时间类型
date:年月日 2021-6-20
datetime:年月日时分秒 2021-6-20 11:11:11
time:时分秒 11:11:11
Year:2021
create table student(<br> id int,<br> name varchar(16),<br> born_year year,<br> birth date,<br> study_time time,<br> reg_time datetime<br>);<br>insert into student values(1,'egon','1880','1880-11-11','11:11:11','2020-11-11 11:11:11');
枚举与集合类型
分类:<br> 枚举(enum):多选一<br> 集合(set):多选多
create table user(<br> id int,<br> name char(16),<br> gender enum('male','female','others')<br>);<br>insert into user values(1,'jason','male'); 正常<br>insert into user values(2,'egon','xxxxooo'); 报错<br># 枚举字段 后期在存数据的时候只能从枚举里面选择一个存储 <br><br><br>create table teacher(<br> id int,<br> name char(16),<br> gender enum('male','female','others'),<br> hobby set('read','DBJ','hecha')<br>);<br>insert into teacher values(1,'jason','male','read'); 正常<br>insert into teacher values(2,'egon','female','DBJ,hecha'); 正常<br>insert into teacher values(3,'tank','others','生蚝'); 报错<br># 集合可以只写一个 但是不能写没有列举的
约束条件
default默认值
# 补充知识点 插入数据的时候可以指定字段<br>create table t1(<br> id int,<br> name char(16)<br>);<br>insert into t1(name,id) values('jason',1);<br><br>create table t2(<br> id int,<br> name char(16),<br> gender enum('male','female','others') default 'male'<br>);<br>insert into t2(id,name) values(1,'jason');<br>insert into t2 values(2,'egon','female');
unique唯一
# 单列唯一<br>create table t3(<br> id int unique,<br> name char(16)<br>);<br>insert into t3 values(1,'jason'),(1,'egon');<br>insert into t3 values(1,'jason'),(2,'egon');<br><br>
# 联合唯一<br>"""<br>ip和port<br>单个都可以重复 但是加载一起必须是唯一的<br>"""<br>create table t4(<br> id int,<br> ip char(16),<br> port int,<br> unique(ip,port)<br>);<br>insert into t4 values(1,'127.0.0.1',8080);<br>insert into t4 values(2,'127.0.0.1',8081);<br>insert into t4 values(3,'127.0.0.2',8080);<br>insert into t4 values(4,'127.0.0.1',8080); 报错
primary key主键
# 1 一张表中有且只有一个主键 如果你没有设置主键 那么会从上往下搜索直到遇到一个非空且唯一的字段将它自动升级为主键<br>create table t6(<br> id int,<br> name char(16),<br> age int not null unique,<br> addr char(32) not null unique<br>);
# 2 如果表中没有主键也没有其他任何的非空且唯一字段 那么Innodb会采用自己内部提供的一个隐藏字段作为主键,隐藏意味着你无法使用到它 就无法提示查询速度
# 3 一张表中通常都应该有一个主键字段 并且通常将id/uid/sid字段作为主键<br>以后我们在创建表的时候id字段一定要加primary key<br>
# 单个字段主键<br>create table t5(<br> id int primary key<br> name char(16)<br>);
# 联合主键(多个字段联合起来作为表的主键 本质还是一个主键)<br>create table t7(<br> ip char(16),<br> port int,<br> primary key(ip,port)<br>);<br><br>
auth_increment自增
# 当编号特别多的时候 人为的去维护太麻烦<br>create table t8(<br> id int primary key auto_increment,<br> name char(16)<br>);<br>insert into t8(name) values('jason'),('egon'),('kevin');
# 注意auto_increment通常都是加在主键上的 不能给普通字段加<br>create table t9(<br> id int primary key auto_increment,<br> name char(16),<br> cid int auto_increment<br>);<br>ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key
delete from t1 删除表中数据后 主键的自增不会停止<br><br>truncate t1 清空表数据并且重置主键
结论
以后在创建表的id(数据的唯一标识id、uid、sid)字段的时候<br>id int primary key auto_increment
视图
什么是视图
视图就是通过查询得到一张虚拟表,然后保存下来,下次可以直接使用<br>其实视图也是表
为什么要用视图
如果要频繁的操作一张虚拟表(拼表组成的),你就可以制作成视图 后续直接操作<br><br>
如何操作
# 固定语法<br>create view 表名 as 虚拟表的查询sql语句<br><br># 具体操作<br>create view teacher2course as<br>select * from teacher INNER JOIN course<br>on teacher.tid = course.teacher_id<br>;
注意:
1 创建视图在硬盘上只会有表结构 没有表数据(数据还是来自于之前的表)<br>2 视图一般只用来查询 里面的数据不要继续修改 可能会影响真正的表<br>3 视图基本上不用不好维护
触发器
概念
在满足对表数据进行增、删、改的情况下,自动触发的功能<br>使用触发器可以帮助我们实现监控、日志...<br>触发器可以在六种情况下自动触发 增前 增后 删前删后 改前改后
语法结构
create trigger 触发器的名字 before/after insert/update/delete on 表名<br>for each row<br>begin<br> sql语句<br>end
# 具体使用 针对触发器的名字 我们通常需要做到见名知意<br># 针对增<br>create trigger tri_before_insert_t1 before insert on t1<br>for each row<br>begin<br> sql语句<br>end<br>create trigger tri_after_insert_t1 after insert on t1<br>for each row<br>begin<br> sql语句<br>end<br>"""针对删除和修改 书写格式一致"""<br><br>ps:修改MySQL默认的语句结束符 只作用于当前窗口<br> delimiter $$ 将默认的结束符号由;改为$$<br> delimiter ;
案例
建表
CREATE TABLE cmd (<br> id INT PRIMARY KEY auto_increment,<br> USER CHAR (32),<br> priv CHAR (10),<br> cmd CHAR (64),<br> sub_time datetime, #提交时间<br> success enum ('yes', 'no') #0代表执行失败<br>);<br><br>CREATE TABLE errlog (<br> id INT PRIMARY KEY auto_increment,<br> err_cmd CHAR (64),<br> err_time datetime<br>);
当cmd表中的记录succes字段是no那么就触发触发器的执行去errlog表中插入数据<br>NEW指代的就是一条条数据对象
写触发器
delimiter $$<br>create trigger tri_after_insert_cmd after insert on cmd <br>for each row<br>begin<br> if NEW.success = 'no' then<br> insert into errlog(err_cmd,err_time) values(NEW.cmd,NEW.sub_time);<br> end if;<br>end $$<br>delimiter ;
朝cmd表插入数据
INSERT INTO cmd (<br> USER,<br> priv,<br> cmd,<br> sub_time,<br> success<br>)<br>VALUES<br> ('jason','0755','ls -l /etc',NOW(),'yes'),<br> ('jason','0755','cat /etc/passwd',NOW(),'no'),<br> ('jason','0755','useradd xxx',NOW(),'no'),<br> ('jason','0755','ps aux',NOW(),'yes');
删除触发器
drop trigger tri_after_insert_cmd;
事务
什么是事务
开启一个事务可以包含多条sql语句 这些sql语句要么同时成功<br>要么一个都别想成功 称之为事务的原子性
事务的作用
"""<br>保证了对数据操作的安全性<br>"""<br>eg:还钱的例子<br> egon用银行卡给我的支付宝转账1000<br> 1 将egon银行卡账户的数据减1000块<br> 2 将jason支付宝账户的数据加1000块<br> <br> 你在操作多条数据的时候可能会出现某几条操作不成功的情况
事务的四大特性
"""<br>ACID<br>A:原子性<br> 一个事务是一个不可分割的单位,事务中包含的诸多操作<br> 要么同时成功要么同时失败<br>C:一致性<br> 事务必须是使数据库从一个一致性的状态变到另外一个一致性的状态<br> 一致性跟原子性是密切相关的<br>I:隔离性<br> 一个事务的执行不能被其他事务干扰<br> (即一个事务内部的操作及使用到的数据对并发的其他事务是隔离的,并发执行的事务之间也是互相不干扰的)<br>D:持久性<br> 也叫"永久性"<br> 一个事务一旦提交成功执行成功 那么它对数据库中数据的修改应该是永久的<br> 接下来的其他操作或者故障不应该对其有任何的影响<br>"""
如何使用事务
# 事务相关的关键字<br># 1 开启事务<br>start transaction;<br># 2 回滚(回到事务执行之前的状态)<br>rollback;<br># 3 确认(确认之后就无法回滚了)<br>commit;
"""模拟转账功能"""<br>create table user(<br> id int primary key auto_increment,<br> name char(16),<br> balance int<br>);<br>insert into user(name,balance) values<br>('jason',1000),<br>('egon',1000),<br>('tank',1000);<br><br><br># 1 先开启事务<br>start transaction;<br># 2 多条sql语句<br>update user set balance=900 where name='jason';<br>update user set balance=1010 where name='egon';<br>update user set balance=1090 where name='tank';<br><br>"""<br>总结<br> 当你想让多条sql语句保持一致性 要么同时成功要么同时失败 <br> 你就应该考虑使用事务<br>"""
存储过程
存储过程就类似于python中的自定义函数<br>它的内部包含了一系列可以执行的sql语句,存储过程存放于MySQL服务端中,你可以直接通过调用存储过程触发内部sql语句的执行
基本使用
create procedure 存储过程的名字(形参1,形参2,...)<br>begin<br> sql代码<br>end<br># 调用<br>call 存储过程的名字();
存储过程演示
delimiter $$<br>create procedure p1(<br> in m int, # 只进不出 m不能返回出去<br> in n int,<br> out res int # 该形参可以返回出去<br>)<br>begin<br> select tname from teacher where tid>m and tid<n;<br> set res=666; # 将res变量修改 用来标识当前的存储过程代码确实执行了<br>end $$<br>delimiter ;<br><br># 针对形参res 不能直接传数据 应该传一个变量名<br># 定义变量<br>set @ret = 10;<br># 执行存储过程<br>call p1(3,5,@ret);<br># 查看变量对应的值<br>select @ret;
pymysql模块中如何调用存储过程
import pymysql<br><br><br>conn = pymysql.connect(<br> host = '127.0.0.1',<br> port = 3306,<br> user = 'root',<br> passwd = '123456',<br> db = 'day48',<br> charset = 'utf8',<br> autocommit = True<br>)<br>cursor = conn.cursor(pymysql.cursors.DictCursor)<br># 调用存储过程<br>cursor.callproc('p1',(1,5,10))<br>"""<br>@_p1_0=1<br>@_p1_1=5<br>@_p1_2=10<br>"""<br># print(cursor.fetchall())<br>cursor.execute('select @_p1_2;')<br>print(cursor.fetchall())
函数
跟存储过程是有区别的,存储过程是自定义函数,函数就类似于是内置函数
自行了解
('jason','0755','ls -l /etc',NOW(),'yes')<br><br>CREATE TABLE blog (<br> id INT PRIMARY KEY auto_increment,<br> NAME CHAR (32),<br> sub_time datetime<br>);<br><br>INSERT INTO blog (NAME, sub_time)<br>VALUES<br> ('第1篇','2015-03-01 11:31:21'),<br> ('第2篇','2015-03-11 16:31:21'),<br> ('第3篇','2016-07-01 10:21:31'),<br> ('第4篇','2016-07-22 09:23:21'),<br> ('第5篇','2016-07-23 10:11:11'),<br> ('第6篇','2016-07-25 11:21:31'),<br> ('第7篇','2017-03-01 15:33:21'),<br> ('第8篇','2017-03-01 17:32:21'),<br> ('第9篇','2017-03-01 18:31:21');<br><br>select date_format(sub_time,'%Y-%m'),count(id) from blog group by date_format(sub_time,'%Y-%m');
流程控制
# if判断<br>delimiter //<br>CREATE PROCEDURE proc_if ()<br>BEGIN<br> declare i int default 0;<br> if i = 1 THEN<br> SELECT 1;<br> ELSEIF i = 2 THEN<br> SELECT 2;<br> ELSE<br> SELECT 7;<br> END IF;<br>END //<br>delimiter ;<br># while循环<br>delimiter //<br>CREATE PROCEDURE proc_while ()<br>BEGIN<br> DECLARE num INT ;<br> SET num = 0 ;<br> WHILE num < 10 DO<br> SELECT<br> num ;<br> SET num = num + 1 ;<br> END WHILE ;
索引
"""<br>1 当表中有大量数据存在的前提下 创建索引速度会很慢<br>2 在索引创建完毕之后 对表的查询性能会大幅度的提升 但是写的性能也会大幅度的降低<br>"""<br>索引不要随意的创建!!!
b+树
"""<br>只有叶子节点存放的是真实的数据 其他节点存放的是虚拟数据 仅仅是用来指路的<br>树的层级越高查询数据所需要经历的步骤就越多(树有几层查询数据就需要几步)<br><br>一个磁盘块存储是有限制的<br>为什么建议你将id字段作为索引<br> 占得空间少 一个磁盘块能够存储的数据多<br> 那么久降低了树的高度 从而减少查询次数<br>"""
聚集索引(primary key)
"""<br>聚集索引指的就是主键 <br>Innodb 只有两个文件 直接将主键存放在了idb表中 <br>MyIsam 三个文件 单独将索引存在一个文件<br>"""
辅助索引(unique,index)
查询数据的时候不可能一直使用到主键,也有可能会用到name,password等其他字段<br>那么这个时候你是没有办法利用聚集索引。这个时候你就可以根据情况给其他字段设置辅助索引(也是一个b+树)
"""<br>叶子节点存放的是数据对应的主键值<br> 先按照辅助索引拿到数据的主键值<br> 之后还是需要去主键的聚集索引里面查询数据<br>"""
覆盖索引
在辅助索引的叶子节点就已经拿到了需要的数据
# 给name设置辅助索引<br>select name from user where name='jason';<br># 非覆盖索引<br>select age from user where name='jason';
0 条评论
下一页
为你推荐
查看更多