《MySQL 数据库 基础知识 笔记---power node》
- 常用的基本指令应用
- 约束
- 级联更新与级联删除
- 存储引擎
- 视图
- DBA指令(了解)
- 数据库设计三范式
- 事务
常用的基本指令应用
数据库管理系统:DBMS
数据库:DB
SQL语句分类:
- DQL语句 :DataBase Query language数据查询语句select
- DML语句 :数据操作语句 insert 、update、delete
- DDL语句: 数据库定义语句 create、drop、alter
- TCL语句: transaction control language事务控制语言,commit rollback
常用指令:
- 查看mysql版本:select version();
- 查看所有数据库:show databases;
- 使用某一个数据库:use 数据库名;
- 查看所有的表:show tables;
- 创建数据库: create database 数据库名;
- 查看当前表在哪个数据库下:select database();
- 查看某张表的结构: desc 表名;
- 查询某个表的某个字段信息:select 字段名 from 表名;
- 查询表的多个字段信息:select 字段名1,字段名2 from 表名;
- 查询某个字段的倍数:例如月薪乘12:select 月薪*12 from 表名;
- 将查询某个字段的倍数取别名: select 月薪12 as 年薪 from 表名; as也可省略,select 月薪12年薪 from 表名;
条件查询:
- 查询员工薪水为5000员工:select salary from 表名 where salary =
5000;在mysql中用单引号引起来也可以,select salary from 表名 where salary = ‘5000’;
若查询的字段是字符串,也用单引号引起来。
- 薪水不等于5000:select salary from 表名 where salary <> 5000;
- 查询薪水大于3600小于5000,select salary from emp where salary >3600 and salary <5000;
- 查询薪水大于1800,并且部门编号为20或30的员工:select salary,name from emp where salary >1800 and (deptNumber=20 or deptNumber = 30);
- 查询属于销售人员和管理人员 :select job,name from emp where job in <‘manager’,‘salesman’>;
排序:单一字段排序用order by 字段名称,order by后面跟上排序名称,排序字段可以放多个,多个采用逗号间隔,order by默认采用升序,如果存在where 子句,那么order by必须放到where后面。
-
按照薪水从小到大升序查找:select name,salary from emp order by salary asc; asc可以不用写,默认升序。
-
按照薪水按降序查找:select name,salary from emp order by salary desc; 如果salary是查询结果的字段从左到右的列数6,可以改写为:select name,salary from emp order by 6 desc; (不建议用数字表示)
-
按照薪水、年龄按降序查找:select name,salary from emp order by salary,age desc; 如果我第一个字段salary重了,那么按照age来降序 。
字符串处理函数:
所有的select 用字符串处理得到的查询结果只是查询时候改变,不会更改数据库的值
- 将员工姓名全部按照大写展示,从emp表中选出:select name as uppername from emp;
- 将员工名字最后显示是只显示其中一部分:select substr(name, 1 ,2) as name from emp; 从名字开始只显示2个字符
- length()查询所有员工的名字的字段长度:select length(name) as namelength from emp;
- round()函数用法:select round(123.56) 表示四舍五入 select round(123.56,1) 四舍五入到1位
- 生成一个0到1的随机数,两边都是闭区间:select rand();
- 匹配工作岗位,当为manager时,薪水上调10%,当为salesman,薪水上调50%,其余不变 :select job,name,(case job when ‘manager’ then salary *1.1 when ‘salesman ’then salary *1.5 else salary end) as newsalary from emp;
- str_to_date 将string转换成日期:select name,date from emp where date=str_to_date(‘12-03-1981’,"%m-%d-%Y’); 告诉mysql,12-03-1981是按照%m-%d-%Y’ 月日年的格式查询 。在实际开发中,将日期定义为DATE类型很少,一般都是使用日期字符串来表示日期。
- date_format函数,将日期转换为特定的字符串:如果数据库中日期是以1998-02-13形式存储,那么select data_format(userdate,’%Y%m%d’) as new date from emp; 会以19980213形式得到结果。
多行处理函数:
- 将所有员工的薪水求和:select sum(salary) as sumsalary from emp;
- 将所有员工的补助、薪水求和 select sum((salary+ifnull(buzhu,0))) as sumsalary from emp;注意,需要通过Ifnull()把buzhu进行判断,如果为Null则赋值为0,不然null进行四则运算整体结果会为null
- 求员工的平均薪水:select avg(salary) as avgsalary from emp;
- 求最大值max() 最小值min() select max(salary) from emp;
- 计数:count()
- 去重distinct::用法,distinct 字段名或者distinct 字段名1,字段名2 。例如查询公司有哪些岗位:select distinct job from emp;
分组查询:
- group by字段名 :找出每个工作岗位的最高薪水:select job,max(salary) as maxsalary from emp group by job;
执行时会先对group by分组,然后求分组中的最大值,
- 求每个部门的平均薪水:select avg(salary) as avgsalary from emp group by department;
- 多个字段分组,按不同部门,不同岗位求最高薪水:select job ,max(salary) as maxsalary from emp group by department,job;
- 多个字段分组,按不同部门,不同岗位,除manager外求最高薪水:select job,max(salary) as maxsalary from emp where job <> ‘manager’ group by job; 其中:where job <> 用于过滤
- 找出每个工作岗位的平均薪水,要求只显示平均薪水大于2000,select job,avg(salary) as avgsalary from emp group by job having avgsalary >2000; 其中:having也是数据过滤语句,但是必须要和group by一起使用
where也可用于数据过滤,where与having区别在于两者 ,一个在group by之前,一个在之后
跨表查询
连接方式分类:
- 内连接: 等值连接、非等值连接、自连接。内连接指的是把表连接时表与表之间匹配的数据行查询出来,就是两张表之间数据行匹配时,要同时满足ON语句后面的条件才行。
- 外连接:左外连接、左连接 右连接、右外连接
- 全连接
根据年代划分SQL语句分SQL92和SQL99两种,只需要掌握SQL99。
SQL92:
select xxx from 表名1,表名2 where 表的连接条件 and 数据过滤条件;
- 笛卡尔积: 若name在emp,dname在department表,查询员工名称与部门名称:select name,dname from emp,dept;
可能会出现迪卡尔积现象:若两张表进行连接查询没有进行任务条件限制,最终查询的结果总数是两张表记录的乘积
- 等值链接:此时是,先做表的笛卡尔积,然后筛选,筛选条件为等值筛选.。若查询dept表和emp表中deptnumber相等的员工:select name,dname from emp as e,dept as d where e.deptnumber = d.deptnumber,
- 不等值链接:----查询员工的姓名,工作,工资,工资等级 select * from emp e,salgrade s where e.sal>=s.losal and e.sal<= s.hisal;
- 自连接:----相当于自己和自己做笛卡尔积 —查询员工姓名,工作,薪资,以及上级领导姓名 selecte1.ename,e1.job,e1.sal,e2.ename from emp e1,emp e2 where e1.mgr=e2.empno;
- 外链接
----左外链接
—查询员工姓名,工作,薪资,部门名称以及没有部门的员工信息
select * from emp e,dept d where e.deptno=d.deptno(+);
----右外链接
—查询员工姓名,工作,薪资,部门名称以及没有员工的部门
select * from emp e,dept d where e.deptno(+)=d.deptno;
SQL99多表查询:
多表连接的语法格式:
select
xxx
from
A表
join
B表
on
连接条件1
join
C表
on
连接条件2;
A表和B表连接按照连接条件1连接,然后A表和C表再通过连接条件2进行连接。
内连接:分为等值连接、非等值连接、自连接。
外连接:A表和B表能够完全匹配的查询记录查询出来外,将其中一张表无条件完全查询出来,对方表没有匹配记录时,会自动模拟null与之匹配。不同于内连接,内连接中不管是等值还是不等值只能查询完全匹配的。
左外连接:包含左表的全部行,以及右边表中全部匹配的行
1.笛卡尔积:使用cross join关键字
-----select 内容 from 表名 cross join
-----查询员工及其部门 select * from emp cross join dept;
2.筛选
自然连接:使用关键字natrual join
----使用:select 内容 from 表名 natural join 表名 select* from emp natural join dept;
特点1:底层是笛卡尔积,按照同名同值字段自动进行等值筛选
缺点1:如果想按照字段名不同,但是字段值不同筛选怎么办?
缺点2:如果只想按照部分字段结果筛选怎么办?
- 解决1:使用using关键字
作用1:指明使用指定的字段对联合查询的结果进行等值筛选
注意:指明的字段必须是两边同名同值字段
使用:select 内容 from 表名 inner join 表名 using(字段名)
select * from emp inner join dept using(deptno,ename);–底层相当于先做了一个笛卡尔积,再进行等值筛选
- 解决2:使用on关键字,进行自定义链接查询
注意:普通筛选使用where筛选不使用on 好处:便于阅读
使用:select 内容 from 表名 inner join 表名 on 连接条件 where 普通筛选条件
select * from emp inner join dept on emp.deptno=dept.deptno where job=‘SALESMAN’;
外连接:
左外连接又称左连接:select 内容 from 表名 left outer join 表名 on 筛选条件
查询员工姓名,工作,薪资,部门名称以及没有部门的员工信息
select * from emp e left outer join dept d on d.deptno=e.deptno;
右外连接又称右连接:select 内容 from 表名 right outer join 表名 on 筛选条件
查询员工姓名,工作,薪资,部门名称以及没有员工的部门
select * from emp e right outer join dept d on d.deptno=e.deptno;
全外连接:select 内容 from 表名 fill outer join 表名 on 筛选条件
select * from emp e full outer join dept d on d.deptno=e.deptno;
自连接
查询员工姓名,工作,薪资,以及上级领导姓名
select e1.*,e2.ename from emp e1 inner join emp e2 on e1.mgr=e2.empno;
多表查询关键字:
- 查询工作岗位为manager和salesman的员工:select ename,job from emp where job = ‘manager’ or job=‘salesman’;或者select ename,job from emp where job in (‘manager’,‘salesman’);
- 使用UNION合并相加结果集:select ename,job from emp where job = ‘manager’ union select ename,job from emp =‘salesman’);但是使用UNION联合结果集,两个结果集的长度必须是一样,字段类型也要相同。
- limit,只在mysql中起作用,获取表的前几行或者中介某几行用法,limit 起始下标m,长度n ,例如获取前五个员工的信息:select * from emp limit 0,5; 如果默认从第一行开始,可以写成select * from emp limit 5; 省略0;
- 使用limit进行分页:是mysql特有的,第一页1,2,3 则limit 0,3 第二页:4,5,6 则limit 3,3 ,第三页:7,8,9 limit 6,3 说明页码pageNo,和页的大小pageSize之间是有关系的,*limit(pageNo-1)pageSize,pageSize
表相关指令
- 创建表:create table t_表名/tbl_表名 ; 通常表名命名为t_表名或者tbl_表名;
其中varchar相比char,都是字符串,varchar比较智能可以根据实际的数据长度分配空间,比较节省空间,但是分配时需要进行判断,效率低。char不需要动态分派空间,执行效率高,但是可能导致空间浪费。
create table t_表名(
字段名名称 字段类型 字段长度 字段约束,
字段名名称 字段类型 字段长度 字段约束,
字段名名称 字段类型 字段长度 字段约束
)
例如:create table t_student(
number int(4),
name varchar(32),
gender char(1),
birthday date,
email varchar(128)
)
- 删除表:drop table t_student; drop table if exists t_student;这样如果表不存在执行也不会报错。
- 复制表:create table emp_bak as select * from emp;
- insert语法:insert into 表名(字段名,字段名,字段名) values (字段值,字段值,字段值);
- update语法:更新记录 :update 表名 set 字段名称=字段值,字段名称=字段值 where 限制条件,update t_student set birth = str_todate(‘1942-10-20’,’%Y-%m-%d) where number = 4;
- delete记录:delete from t_student ;//删除t_student所有数据。 delete from t_student where number = 4;
- 快速插入:insert into emp_bak select * from emp where job = ‘manager’;
- 修改表:alter table 表名t_student add 字段名 字段类型(长度); alter table t_student add email varchar(128); alter table t_student modify 表中存在的字段名 字段类型(长度); alter table t_student drop email; 可以删除某一字段所有内容;
not null和unique可以联合使用。
alter table 表名 add
alter table 表名 modify 字段名称 字段类型 字段长度 字段约束
alter table 表名 drop 字段名称
alter table 表名 change 原字段名 新字段名
约束
约束:是对表中的数据的限制条件,constraint。
常见的约束:
- 非空 not null
- 唯一约束 unique,列级约束,表示字段具有唯一性,不可重复,create table t_user(id int(4),name varchar (32) not null,email varchar(128) unique); unique可以联合约束:create table t_user(id int(4),name varchar(32) not null,email varchar(128), unique(name,email));这样只有插入的name 和email都不同时,才会表示有冲突。
- 唯一约束 unique,表级约束,create table t_user(id int(4),name varchar(32) not null,email varchar(128), constraint t_user_name_email_unique unique(name,email));
- 主键约束primary key,某个字段添加主键后,效果相当于not null ,unique相同,但是主键约束还会自动添加索引 根据个数分为单一主键和复合主键,mysql中提供了auto_increment自增生成主键值。分列级写法和表级写法。
列级主键约束:
create table t_user(
id int(4) primary key auto_increment,
name varchar(32) not null
);
表级主键约束:跟列级约束写法不同,
create table t_user(
id int(4) ,
name varchar(32) not null,
primary key(id,name)
);
外键约束foreigh key
实际场景应用:原始设计的表:t_student ,存在数据冗余情况,一行就有一个cname,导致表变太大。
将班级的信息单独创建一张表t_class,新的t_student表如下:而此时为了保证classno来自于t_class中的Cno,则必须为t_student中的classno添加外键约束,classno就是外键,此时为单一外键。classno要添加外键约束,表示classno只能从t_class中的cno中去。
t_class表:
需要注意的是:
- 外键字段可以为NULL,外键为空的数据也叫孤儿数据
- 被引用字段t_class中的cno必须具有unique约束,不然无法由学生con定位到班级
- 有了外键引用之后,表分为父表和子表,以上父表:班级表t_ class;子表是:学生表t_ student;创建表时先创建父表,再创建子表;插入数据时,先插入父表数据再插入子表数据
select s.sname,c.cname from t_student s join t_class c on s.classno = c.cno;
级联更新与级联删除
用法:级联更新与级联删除必须使用在外键约束情况下,谨慎使用,在添加级联更新与级联删除的时候,需要在外键约束后面添关键字,注意:级联更新与级联删除操作谨慎使用,因为级联操作会将数据改变或者删除【数据无价】
外键约束没有提供更改语句,只能先删除再添加
删除外键语句:
添加外键约束语句,并加入级联删除 on delete cascade
此时,才能删除t_class中班级的编号为200的学生信息:
级联更新:
步骤1、删除外键约束(没有修改外键约束语法)
步骤2、更新外键约束和添加级联更新功能 on update cascade
步骤3、更新t_class表中班级编号200改为100,包括所在班级的学生信息
存储引擎
通过指令:show engines;查看
若创建表时没有指定存储引擎,那么会按照my.ini配置文件使用的default-storage-engin选项,默认创建。当然也可手动指定:
如果有需要修改存储引擎:alter table 表名 engine = 存储引擎名称;
常见的存储引擎:
- MyISAM,使用三个文件存储表的结果、数据、索引,可转换为压缩、只读表来节省空间
a)格式文件一存储表的结构(mytable.frm )
b)数据文件一存储表的数据(mytabIe.MYD )
c)索引文件一存储表的索引(mytabIe.MYI )
- INNODB是MySQL数据库的缺省引擎,
每个InnoDB表在数据库目录中以.frm格式文件表示 InnoDB表空间tablespace被用于存储表的内容
提供一组用来记录事务性活动的日志文件 用COMMIT(提交)、SAVEPOINT及ROLLBACK(回滚)支持事务处理
提供全部ACID兼容
在MySQL服务器崩溃后提供自动恢复
多版本(MVCC)和行级锁定
支持外键及引用的完整性,包括级联更新和删除
- MEMORY存储引擎,使用MEMORY存储引擎的表,因为数据存储在内存中,且行的长度固定,所以使得MEMORY存储引擎非常快,在数据库目录内,每个表均以frm格式文件表示
表数据及索引被存储在内存中; 表级锁机制; 字段属性不能包含TEXT或BLOB字段;
选择合适的存储引擎:
- MyISAM表最适合于大量的数据读而少量数据更新的混合操作。MyISAM表的另一种适用情形是使用压缩的只读表。
- 如果查询中包含较多的数据更新操作,应使用InnoDB。其行级锁机制和多版本的支持为数据读取和更新的混合提供了良好的并发机制。
- 使用MEMORY存储引擎存储非永久需要的数据,或者是能够从基于磁盘的表中重新生成的数据。
查看索引指令:show index from 表名;
创建索引:create index 索引名 on 表名(列名);
删除索引 :drop index 索引名 on 表名;
视图
视图在数据库管理系统中也是一个对象,也是以文件形式存在的。视图也对应了一个查询结果,只是从不同的角度查看数据。
创建视图:create view视图名称 as 查询语句;
删除视图:语法结构:drop view if exists视图名称:
修改视图:alter view视图名称as查询语句
视图的作用:面向视图查询,可以提高查询效率,隐藏表的实现细节
例如:
DBA指令(了解)
DBA工程师,
新建用户:CREATE USER username IDENTIFIED BY ‘password’;
授权:
回收授权:
导入导出
数据库设计三范式
1、第一范式:主键和字段不能在分,主键中不能出现重复记录,每个字段是原子性,不能再分
修改以上表:
第一范式的结论:
- 每一行必须唯一,也就是每个表必须有主键,这是我们数据库设计的最基本要求
- 主键主要通常采用数值型或定长字符串表示
- 关于列不可再分,应根据具体的情况来决定
2、第二范式:第二范式是建立在第一范式基础之上,要求非主键字段完全依赖主键,注意:尽量不要使用联合主键
例如下图中,将学生编号和教师编号作为联合主键:
分析:1、以上虽然确定了主键,但此表会出现大量冗余,主要涉及到的冗余字段为”学生姓名“和“教师姓名’‘
2、出现冗余的原因在于:学生姓名部分依赖了主键的一个字段学生编号,而没有依赖教师编号,而教师姓名部分依赖了主键的一个字段教师编号,这就是第二范式部分依赖。
学生姓名和教师姓名都没有完全依赖主键,而是依赖了其中的部分的主键,因此尽量不要使用联合主键。
解决办法:创建一张学生表,只存放学生编号和姓名。创建一张老师表,只存放教师编号和教师姓名。但是需要,再增加一张表,教师和学生的关系表:关系表中,学生编号必须来自学生表,教师编号必须来自教师表,这两个字段都要有外键约束。
3、第三范式:在建立第二范式基础上,要求非主键字段不能产生传递依赖于主键字段。
学生信息和班级是1对多情况,班级名称字段存在冗余,因为班级名称字段没有直接依赖于主键,班级名称字段依赖于班级编号,班级编号依赖于学生编号,那么这就是传递依赖。
三范式经典设计总结
一对一:可以两者共享主键,也可两个主键,但是其中一个主键是另一张表的唯一约束的外键。
一对多:分两张表存储,在多的一方添加外键,这个外键字段引用一的一方中的主键字段例如:学生信息表和班级信息表,
多对多:分三张表存储,在学生表中存储学生信息,在课程表中存储课程信息,在选课表中存储学生选课信息,请参考:
事务
事务一个最小的不可再分的工作单元,通常一个事务对应一个完整的业务,而一个完整的业务需要批量的DML(insert, update, delete)语句共同完成。只有DML语句才有事务。
四个特性:
- A(Atomitic):事务有原子性,不可分割
- C(consistency):一致性,事务要求所有的DML语句操作的时候,必须保证同时成功或同时失败
- I(Isolate):隔离性:一个事务不会影响其它事务的运行
- D(Durable):持久性:在事务完成之后,该事务对数据库所作的更改将持久地保存在数据库中
事务的基本概念:
- 开启事务:start transaction
- 结束事务:end transaction
- 提交事务:commit transaction
- 回滚事务:rollback transaction
事务开启和结束的标志是什么?
- 开启的标志:任何一条DML语句执行,标志事务的开启
- 结束的标志:提交(commit)或者回滚(rollback)
其中,提交是成功的结束,将所有的DML语句操作记录和底层硬盘文件中数据进行一次同步。回滚是失败的结束,会将所有DML语句操作记录全部清空。需要注意的是在事务进行过程中,未结束之前,DML语句是不会修改底层数据库文件中的数据。
Mysql事务提交实例
MySQL默认事务:自动提交show variables like `%commit%’;
在MySQL数据库管理系统中,默认情况下,事务是自动提交的;也就是说,只要执行一条DML语句,就开启了事务,并且提交了事务;
可以关闭自动提交事务,改成手动
事务成功用法:start transaction;commit;
- 第一步:start transaction;手动开启事务
- 第二步:DML语句.…
- 执行批量DML语句
- 第三步:commit;
- 手动提交事务【事务成功结束】
演示例子:在t_user表中插入数据:事务成功提交
如果只选了事务回滚,是查询不到插入的语句。
事务的隔离级别
如何理解读未提交、读已提交、可重复读、串行化?
- read committed读未提交(由于隔离级别级别最低存在脏读情况),事务A和和事务B,事务A未提交的数据,事务B可以读取,这里读取到的数据可以叫做”脏数据",或”脏读Dirty Read",读未提交隔离级别最低,这种级别一般只在理论上存在,数据库默认隔离级别一般都高于该隔离级别。
- read committed读已提交(虽然解决了脏读的情况,该隔离级别高于读未提交,但是正是因为读已提交,导致其他事务提交后,我能读取到问题,理论上事务之间的读取应该隔离,不影响,我应该要可以重复读,因此现在多了一个不可重复读的问题)。该隔离级别可以避免脏数据,但是导致”不可重复读取。
- repeatable read可重复读(此时这种隔离级别可以避免粗庄读和不可重复读“,达到”重复读取“;,其他事务提交后,我不会读取到,但是如果事务A提交了数据,事务C提交了数据,但是事务B一直都读取的是不变的数据,导致了幻读)
- serializable串行化:事务A和事务B,事务A在操作数据库表中数据的时候,事务B只能排队等待,这种隔离级别可以避免”幻象读“,每一次读取都是数据库表中真实的记录,这种事务隔离级别一般很少使用,吞吐量太低,用户体验不好
MYSQL默认是可重复读,第三种隔离级别。
更改Mysql隔离级别:
事务隔离级别的作用范围分为两种:会话级、全局级:
事务隔离级别的作用范围分为两种:会话级、全局级
查看隔离级别: