- 一、数据库概述及数据准备:
- ①SQL、DB、DBMS:
- ②表_table:
- ③SQL语句分类:
- ④导入数据:
- ⑤查看表结构:
- ⑥查看表中的数据:
- 二、常用命令:
- ①查看MySQL版本:
- ②创建数据库:
- ③查询当前使用的数据库:
- ④终止语句:
- ⑤退出MySQL:
- ⑥查看创建表的语句:
- 三、简单的查询
- 四、条件查询:
- 五、数据排序
- 六、分组函数和分组查询
- ①分组函数:
- ②分组查询:
- ③小结:
- 七、连接查询
- ①什么是连接查询?
- ②连接查询的分类:
- ③笛卡尔积现象:
- ④内连接之等值连接:
- ⑤内连接之非等值连接:
- ⑥自连接:
- ⑦外连接:
- ⑧多张表进行操作:
- 八、子查询:
- 九、`union`
- 十、`limit`
- 十一、表及数据的增删查改
- ①表的创建_`create`:
- ②数据的插入_`insert`:
- ③修改数据_`update`:
- ④表及数据的删除:
- 十二、表结构的增删改
- ①添加字段:
- ②修改字段:
- ③删除字段:
- 十三、创建表加上约束
- ①非空约束_`not null`:
- ②唯一性约束_`unique`:
- ③主键约束:
- ④外键约束:
- ⑤级联更新与级联删除:
- 十四、存储引擎
- ①什么是存储引擎?
- ②存储引擎的使用:
- ③常用的存储引擎:
- ④存储引擎的选择:
- 十五、事务
- ①基本介绍:
- ②自动提交模式:
- ③事务的隔离级别:
- ④演示事务:
- ⑤设置服务器缺省隔离级别:
- 十六、索引
- ①索引原理:
- ②索引的相关使用:
- ③索引的分类:
- ④索引什么时候失效?
- 十七、视图
- ①视图的基本介绍:
- ②视图的使用:
- 十八、DBA命令
- ①将数据库中的数据导出:
- ②导入数据:
- 十九、数据库设计三范式
- ①什么是设计范式?
- ②三范式的基本介绍:
- ③三范式小结:
- END
-
DB:
- Database——数据库,数据库实际上在硬盘上以文件的形式存在。
-
DBMS:
- D a t a base M a n a g e m e n t S y s t e m Database Management System DataBaseManagementSystem——数据库管理系统,常见的有:MySQL、Oracle、SQLServer……
-
SQL:
- 结构化查询语言,是一门标准通用的语言,标准的 SQL 语句适合于所有的数据库产品;SQL 属于高级语言;SQL 语句在执行的时候,实际上内部也会先进行编译,然后再执行 SQL,SQL 语句的编译由 DBMS 完成。
-
彼此之间的关系:
- DBMS负责执行 SQL 语句,通过执行 SQL语句来操作 DB中的数据。
- DBMS—(执行)—>SQL—(操作)—>DB。
-
什么是表?
- table 是数据库的基本组成单位,所有的数据都以表格的形式组织,目的是可读性强。
-
一个表包含行和列:
-
行——被称为数据/记录(data)。
-
列——被称为字段(column)
学号(int) 姓名(varchar) 年龄(int) 20181101 张三 21 20181103 李四 22 -
每一个字段应该包含哪些属性?
- 字段名、数据类型、相关的约束。
-
| 分类 | 介绍 |
|---|---|
| DQL(数据查询语言) | 查询语句,凡是select语句都是DQL。 |
| DML(数据操作语言) | insert delete update,对表当中的数据进行增删改。 |
| DDL(数据定义语言) | create drop alter,对表结构的增删改。 |
| TCL(事务控制语言) | commit提交事务,rollback回滚事务。(TCL中的T是Transaction) |
| DCL(数据控制语言) | grant授权、revoke撤销权限等。 |
-
登录 MySQL 数据库管理系统:
mysql -uroot -p密码
-
查看有哪些数据库:
show databases;
-
创建自己的数据库:
create database 数据库名;
-
使用数据库的数据:
use 数据库名;
-
查看当前使用的数据库中有哪些表:
show tables;
- 因为是新建的数据库,所以内部暂时还空空如也。
-
初始化数据:
source sql文件路径;
-
test.sql,这个文件以 sql 结尾,这样的文件被称为“sql脚本”。什么是 sql 脚本呢?
-
当一个文件的扩展名是.sql,并且该文件中编写了大量的sql语句,我们称这样的文件为sql脚本。
- 注意:直接使用source命令可以执行sql脚本。
- sql脚本中的数据量太大的时候,无法打开,请使用source命令完成初始化。
-
test.sql 文件中的代码:
DROP TABLE IF EXISTS EMP; DROP TABLE IF EXISTS DEPT; DROP TABLE IF EXISTS SALGRADE; CREATE TABLE DEPT (DEPTNO int(2) not null , DNAME VARCHAR(14) , LOC VARCHAR(13), primary key (DEPTNO) ); CREATE TABLE EMP (EMPNO int(4) not null , ENAME VARCHAR(10), JOB VARCHAR(9), MGR INT(4), HIREDATE DATE DEFAULT NULL, SAL DOUBLE(7,2), COMM DOUBLE(7,2), primary key (EMPNO), DEPTNO INT(2) ) ; CREATE TABLE SALGRADE ( GRADE INT, LOSAL INT, HISAL INT ); INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 10, 'ACCOUNTING', 'NEW YORK'); INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 20, 'RESEARCH', 'DALLAS'); INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 30, 'SALES', 'CHICAGO'); INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 40, 'OPERATIONS', 'BOSTON'); commit; INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7369, 'SMITH', 'CLERK', 7902, '1980-12-17' , 800, NULL, 20); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20' , 1600, 300, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7521, 'WARD', 'SALESMAN', 7698, '1981-02-22' , 1250, 500, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7566, 'JONES', 'MANAGER', 7839, '1981-04-02' , 2975, NULL, 20); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28' , 1250, 1400, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01' , 2850, NULL, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7782, 'CLARK', 'MANAGER', 7839, '1981-06-09' , 2450, NULL, 10); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19' , 3000, NULL, 20); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7839, 'KING', 'PRESIDENT', NULL, '1981-11-17' , 5000, NULL, 10); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08' , 1500, 0, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7876, 'ADAMS', 'CLERK', 7788, '1987-05-23' , 1100, NULL, 20); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7900, 'JAMES', 'CLERK', 7698, '1981-12-03' , 950, NULL, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7902, 'FORD', 'ANALYST', 7566, '1981-12-03' , 3000, NULL, 20); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7934, 'MILLER', 'CLERK', 7782, '1982-01-23' , 1300, NULL, 10); commit; INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 1, 700, 1200); INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 2, 1201, 1400); INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 3, 1401, 2000); INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 4, 2001, 3000); INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 5, 3001, 9999); commit;- 执行完命令之后,我们再次查看数据库中的表:
-
-
删除数据库:
drop database 数据库名字;
- 这个就不演示了,整完还得我重建!/(ㄒoㄒ)/~~
+----------------+ | Tables_in_test | +----------------+ | dept |(部门表) | emp |(员工表) | salgrade |(工资等级表) +----------------+
- 部门表:
mysql> desc dept; +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | DEPTNO | int(2) | NO | PRI | NULL | |部门编号 | DNAME | varchar(14) | YES | | NULL | |部门名称 | LOC | varchar(13) | YES | | NULL | |部门地址 +--------+-------------+------+-----+---------+-------+ 3 rows in set (0.01 sec)
- 员工表:
mysql> desc emp; +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | EMPNO | int(4) | NO | PRI | NULL | |员工编号 | ENAME | varchar(10) | YES | | NULL | |员工姓名 | JOB | varchar(9) | YES | | NULL | |工作岗位 | MGR | int(4) | YES | | NULL | |上级领导编号 | HIREDATE | date | YES | | NULL | |入职日期 | SAL | double(7,2) | YES | | NULL | |薪资水平 | COMM | double(7,2) | YES | | NULL | |津贴 | DEPTNO | int(2) | YES | | NULL | |部门编号 +----------+-------------+------+-----+---------+-------+ 8 rows in set (0.01 sec)
- 工资等级表:
mysql> desc salgrade; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | GRADE | int(11) | YES | | NULL | |等级 | LOSAL | int(11) | YES | | NULL | |最低薪资 | HISAL | int(11) | YES | | NULL | |最高薪资 +-------+---------+------+-----+---------+-------+ 3 rows in set (0.01 sec)⑥查看表中的数据:
mysql> select* from dept; +--------+------------+----------+ | DEPTNO | DNAME | LOC | +--------+------------+----------+ | 10 | ACCOUNTING | NEW YORK | | 20 | RESEARCH | DALLAS | | 30 | SALES | CHICAGO | | 40 | OPERATIONS | BOSTON | +--------+------------+----------+ 4 rows in set (0.00 sec)
mysql> select* from emp; +-------+--------+-----------+------+------------+---------+---------+--------+ | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | +-------+--------+-----------+------+------------+---------+---------+--------+ | 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 | | 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 | | 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 | | 7566 | JonES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 | | 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | | 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 | | 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | | 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | | 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 | | 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | | 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 | | 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 | | 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | | 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 | +-------+--------+-----------+------+------------+---------+---------+--------+ 14 rows in set (0.00 sec)
mysql> select* from salgrade; +-------+-------+-------+ | GRADE | LOSAL | HISAL | +-------+-------+-------+ | 1 | 700 | 1200 | | 2 | 1201 | 1400 | | 3 | 1401 | 2000 | | 4 | 2001 | 3000 | | 5 | 3001 | 9999 | +-------+-------+-------+ 5 rows in set (0.00 sec)
二、常用命令: ①查看MySQL版本:
-
未登录MySQL之前:
mysql -V mysql --version
- MySQL程序选项具有如下两种通用形式:
- 长选项——由单词之前加两个减号组成。
- 短选项——由单个字母之前加一个减号组成。
- MySQL程序选项具有如下两种通用形式:
-
登录MySQL之后:
select version();
create database 数据库名;
-
在创建完数据库,建立表之前必须要先选择数据库:
use 数据库名称;
select database();④终止语句:
c⑤退出MySQL:
q quit exit⑥查看创建表的语句:
show create table 表名;
三、简单的查询
-
语法格式:
select 字段名1,字段名2,字段名3,.... from 表名;
-
注意:
- 任何一条sql语句以;结尾。
- sql语句不区分大小写。
-
使用举例:
- 查询员工的年薪(字段可以参与数学运算)
- 给查询结果的列重命名(as可以省略)
- 别名中含有中文(中文一定要使用''括起来,MySQL也支持"",但尽量别用)
- 查询所有字段(实际开发中不建议使用*,效率较低)
四、条件查询:
-
语法格式:
select 字段,字段... from 表名 where 条件;
-
执行顺序:先from,然后where,最后select。
-
支持的运算符:
运算符 说明 = 等于 <>或!= 不等于 < 小于 <= 大于等于 > 大于 >= 大于等于 between...and... 两个值之间,等同于>= and <= is null 为null(is not null不为空) and 并且 or 或者 in 包含,相当于多个or(not in不在这个范围中) not not可以取非,主要用在is或in中 like like称为模糊查询,支持%或下划线_匹配 -
使用举例:
- 查询工资等于5000的员工姓名
- 查询SMITH的工资
- 找出工资高于3000的员工(大于等于、小于、小于等于都一样的书写格式)
-
找出工资不等于3000的
-
找出工资在1100和3000之间的员工,包括1100和3000
- between...and...是闭区间,在使用的时候必须左小右大。
- between...and...除了可以使用在数字方面之外,还可以使用在字符串方面,此时为左闭右开。
- 找出哪些人津贴为NULL:
- 在数据库当中NULL不是一个值,代表什么也没有,为空。空不是一个值,不能用等号衡量。必须使用is null或者is not null。
- 找出工作岗位是MANAGER或SALESMAN的员工
- and 和 or 联合起来使用:找出薪资大于1000的并且部门编号是20或30部门的员工。(当运算符的优先级不确定的时候加小括号。)
- in 等同于or:找出工作岗位是MANAGER和SALESMAN的员工
-
模糊查询like:
- 在模糊查询当中,必须掌握两个特殊的符号,一个是%,一个是_,%代表任意多个字符,_代表任意1个字符。
- 找出名字中含有O的
- 找出名字中第二个字母是A的
- 找出名字中有下划线_的
- 因为下划线_表示任意的一个字符,所以加上来表示_本身来使用,%也是类似的。
- 找出名字最后的一个字符是T的
五、数据排序
排序采用 order by 子句,order by 后面跟上排序字段,排序字段可以放多个,多个采用逗号间隔,order by 默认采用升序,如果存在 where 子句那么 order by 必须放到 where 语句的后面。
- 按照工资升序,找出员工名字和薪资:
select ename,sal from emp order by sal;
- 注意:默认是升序。但是我们可以指定升序或者降序——asc表示升序,desc表示降序。
- 使用多个排序条件:按照工资的降序排列,当工资相同的时候再按照名字的升序排列。
-
注意:越靠前的字段越能起到主导作用。只有当前面的字段无法完成排序的时候,才会启用后面的字段。
-
和where联合起来使用:存在 where 子句那么 order by 必须放到 where 语句的后面。
select 执行顺序 字段 3 from 表名 1 where 条件 2 order by .... 4 order by是最后执行的。
- 找出工作岗位是SALESMAN的员工,并且要求按照薪资的降序排列。
- 使用字段的位置进行排序:不建议使用此种方式,采用数字含义不明确,程序健壮性不好。
六、分组函数和分组查询 ①分组函数:
- 所有的分组函数都是对“某一组”数据进行操作的。分组函数还有另一个名字:多行处理函数。多行处理函数的特点:输入多行,最终输出的结果是1行。
| 字段名 | 意义 |
|---|---|
| count | 取得记录条数 |
| sum | 求和 |
| avg | 取得平均数 |
| max | 取得最大的数 |
| min | 取得最小的数 |
-
注意:
- ①分组函数自动忽略空值,不需要手动加where条件来排除空值。
- ②分组函数不能直接使用在where关键字后面。
-
count:取得记录条数。
- 取得所有的员工数:
- Count(*)表示取得所有记录,不是统计某个字段中数据的个数,而是统计总记录条数(和某个字段无关),忽略 null,为 null 的值也会取得。
- 取得津贴不为null员工数:
- 采用 count(字段名称),表示统计字段中不为null的数据总数量,不会取得为 null 的记录。
- 取得工作岗位的个数:
- 使用distinct目的是为了去重,后面小结板块会详细讲讲。
-
sum:sum会取得某一列的和,null会自动忽略。
- 取得薪水的和:
- 取得津贴的和:null会被自动忽略。
- 取得薪水的合计:
- 从以上结果来看,不正确,原因在于 comm 字段有 null 值,所以无法计算,sum 会忽略掉,正确的做法是将 comm 字段转换成 0;为此我们要借助ifnull()空处理函数——可能为NULL的数据,被当做什么处理。
-
avg:取得某一列的平均值
- 取得平均薪水:
-
max:取得某一列的最大值。
- 取得最高薪水:
- 取得最晚入职得员工:
-
min:取得某个一列的最小值。
- 取得最低薪水:
- 取得最早入职得员工(可以不使用 str_to_date 转换)
-
分组函数也可以组合起来用:
-
但是切记:分组函数不能直接使用在where关键字后面。
-
可以分布执行来解决上面提出的不能在where关键字后面使用分组函数的问题(语句嵌套),例如:找出工资高于平均工资的员工。
- 算出平均工资:
- 找出高于平均工资的员工:
- 最终整合:
-
-
group by : 按照某个字段或者某些字段进行分组。
- 实际举例:找出每个工作岗位的最高薪资:
-
注意:分组函数一般都会和group by联合使用,这也是为什么它被称为分组函数的原因。 并且任何一个分组函数count、sum、avg、max、min都是在group by语句执行结束之后才会执行的。当一条sql语句没有group by的话,整张表的数据会自成一组。
-
书写注意:
select ename,max(sal),job from emp group by job;
-
以上在mysql当中,查询结果是有的,但是结果没有意义,在Oracle数据库当中会报错。语法错误。Oracle的语法规则比MySQL语法规则严谨。
-
记住一个规则:当一条语句中有group by的话,select后面只能跟分组函数和参与分组的字段。
-
having : 对分组之后的数据进行再次过滤。
- 实际举例:取得每个岗位的平均工资大于 2000
-
特殊情况:但是有一些情况下的查询可以不必使用having就能实现,并且效率更快。
-
找出每个部门的最高薪资,要求显示薪资大于2900的数据。
- 找到每个部门的最高薪资
- 找到薪资大于2900的
- 可以不借助having在where中就可以实现上述功能
-
这样的效率较高,建议能够使用where过滤的尽量使用where,因为where的执行顺序在having前面,早一步过滤的话可以减少处理的数据量,提高效率(但是谨记一点:where后面不能使用分组函数,这个使用就只能使用having了)。
-
-
一个完整的DQL语句:
执行顺序 select 5 ... from 1 ... where 2 ... group by 3 ... having 4 ... order by 6 ...
- 个人理解:先知道要处理什么表(from),再通过条件(where)选中原表中的一些行,对于这些行进行分组(group up),分完组之后再度过滤(having),然后通过(select)构建新表的列;最终排序(order by)呈现新表。
-
对于查询结果集的去重_distinct:
- 查看所有的工作种类:
-
错误举例:
select ename,distinct job from emp;
- 以上的sql语句是错误的,distinct只能出现在所有字段的最前面。
-
其他正确使用举例:
select distinct deptno,job from emp;
select count(distinct job) from emp;
七、连接查询 ①什么是连接查询?
- 在实际开发中,大部分的情况下都不是从单表中查询数据,一般都是多张表联合查询取出最终的结果。在实际开发中,一般一个业务都会对应多张表,比如:学生和班级,起码两张表。
- 连接查询:也可以叫跨表查询,需要关联多个表进行查询。
-
根据语法出现的年代来划分的话,包括:
- SQL92(一些老的DBA可能还在使用这种语法。DBA:Database Administrator,数据库管理员)
- SQL99(比较新的语法)
-
根据表的连接方式来划分,包括:
在表的连接查询方面有一种现象被称为:笛卡尔积现象。(笛卡尔乘积现象)
- 实际举例:找出每一个员工的部门名称,要求显示员工名和部门名。
- 笛卡尔积现象:当两张表进行连接查询的时候,没有任何条件进行限制,最终的查询结果条数是两张表记录条数的乘积。
-
书写小技巧:给表起别名(以上面的查询案例举例)
select e.ename,d.dname from emp e,dept d;
- 起别名的好处:执行效率高,可读性好。
-
如何避免笛卡尔积现象——加条件进行过滤(还是以上面的查询案例举例:找出每一个员工的部门名称,要求显示员工名和部门名)。
- 避免了笛卡尔积现象,并不会减少记录的匹配次数,次数还是56次。只不过显示的是有效记录。
-
最大的特点——条件为等量关系。
-
实际举例:查询每个员工的部门名称,要求显示员工名和部门名。
- SQL92:比较老旧的语法,不怎么使用了。
-
SQL99:现在比较常用的语法。
- 或者,inner可以省略的,带着inner目的是可读性好一些。
select e.ename,d.dname from emp e inner join dept d on e.deptno = d.deptno;
- 语法:SQL99语法结构更清晰一些,表的连接条件和后来的where条件分离了。
... A (inner) join B on 连接条件 where ...
-
最大的特点——连接条件中的关系是非等量关系。
-
实际举例:找出每个员工的工资等级,要求显示员工名、工资、工资等级。
- 辅助信息:
- 查询结果:
- 最大的特点——一张表看做两张表来用,自己连接自己。
- 实际举例:找出每个员工的上级领导,要求显示员工名和对应的领导名。
-
什么是外连接,和内连接有什么区别?
- 内连接:假设A和B表进行连接,使用内连接的话,凡是A表和B表能够匹配上的记录查询出来,这就是内连接。AB两张表没有主副之分,两张表是平等的。
- 外连接:假设A和B表进行连接,使用外连接的话,AB两张表中有一张表是主表,一张表是副表,主要查询主表中的数据,捎带着查询副表,当副表中的数据没有和主表中的数据匹配上,副表自动模拟出NULL与之匹配。
-
外连接的分类?
-
左外连接(左连接):表示左边的这张表是主表。
表 1 left outer join 表 2 on 关联条件
-
右外连接(右连接):表示右边的这张表是主表。
表 1 right outer join 表 2 on 关联条件
-
左连接有右连接的写法,右连接也会有对应的左连接的写法。
-
-
实际举例:找出每个员工的上级领导?(所有员工必须全部查询出来。)
- 内连接:
- 外连接(左外连接/左连接)(outer可以省略)(a为主表):
- 外连接(右外连接/右连接)(outer可以省略)(a为主表):
- 外连接最重要的特点是:主表的数据无条件的全部查询出来。
-
联合使用:找出哪个部门没有员工?
- 辅助信息:
- 查询结果:
-
以三张表为例:A表和B表先进行表连接,连接之后继续和C表进行连接。
.... A join B join C on ...
-
实际举例:
- 找出每一个员工的部门名称以及工资等级。
- 找出每一个员工的部门名称、工资等级、以及上级领导。
- 在书写上面的案例时,自己有一个小心得——左外和右外连接的使用时机要把握好,不然就起不到理想的效果(譬如下面就是用早了,导致不是每一个员工都显示出来了)。
八、子查询:
-
什么是子查询?子查询都可以出现在哪里?
- select语句当中嵌套select语句,被嵌套的select语句是子查询。
-
子查询可以出现在哪里?
select ..(select). from ..(select). where ..(select).
-
where子句中使用子查询:
-
找出高于平均薪资的员工信息(where后面不能直接使用分组函数)。
- 找出平均薪资:
- 使用where对于原表进行过滤:
- 合并上面两步:
-
-
from后面嵌套子查询:
-
找出每个部门平均薪水的等级。
- 找出每一个部门的平均薪水(按照部门编号进行分组,求sal的平均值)
- 将以上的查询结果当做临时表t,让t表和salgrade表进行连接
-
-
在select后面嵌套子查询:
-
找出每个员工所在的部门名称,要求显示员工名和部门名。
- 做法一:
- 做法二:
-
九、union
union 可以合并集合,也就是可以将查询结果集相加。
-
实际案例:找出工作岗位是SALESMAN和MANAGER的员工?
- 方法一_or:
-
方法二_in:
-
方法三_union:
-
注意:合并结果集的时候,需要查询字段个数相同,而且还要求类型对应相同。
十、limit
-
特点介绍:
-
limit是MySQL特有的,其他数据库中没有,不通用。(Oracle中有一个相同的机制,叫做rownum)。
-
limit取结果集中的部分数据,这是它的作用。
-
-
语法机制:
limit startIndex, length
- startIndex表示起始位置,默认从0开始,0表示第一条数据,length表示取几个。
- 实际举例:取出工资前5名的员工(降序取前5个)
-
limit是sql语句最后执行的一个环节:
执行顺序 select 5 ... from 1 ... where 2 ... group by 3 ... having 4 ... order by 6 ... limit 7 ...;
十一、表及数据的增删查改 ①表的创建_create:
-
建表的语法格式:
create table 表名( 字段名1 数据类型, 字段名2 数据类型, 字段名3 数据类型, .... );
-
sql中字段常见的数据类型:
类型 介绍 int 整数型(Java中的int) bigint 长整型(Java中的long) float 浮点型(Java中的float、double char 定长字符串(String) varchar 可变长字符串(StringBuffer、StringBuilder) date 日期类型 (对应Java中的java.sql.Date类型) BLOB 二进制大对象(存储图片、视频等流媒体信息) Binary Large Object (对应Java中的Object) CLOB 字符大对象(存储较大文本,比如,可以存储4G的字符串。) Character Large OBject (对应Java中的Object) ...... -
char和varchar怎么选择?
- 在实际的开发中,当某个字段中的数据长度不发生改变的时候,是定长的,例如:性别、生日等都是采用char。
- 当一个字段的数据长度不确定,例如:简介、姓名等都是采用varchar。
-
表名在数据库当中一般建议以:t_或者tbl_开始。
创建学生表: 学生信息包括: 学号、姓名、性别、班级编号、生日 学号:bigint 姓名:varchar 性别:char 班级编号:int 生日:char create table t_student( no bigint, name varchar(255), sex char(1), classno varchar(255), birth char(10) );
-
表的复制:
create table 表名 as select语句; //将查询结果当做表创建出来。
-
语法格式:
insert into 表名(字段名1,字段名2,字段名3,....) values(值1,值2,值3,....)
- 要求:字段的数量和值的数量相同,并且数据类型要对应相同。
-
实际举例:
INSERT INTO t_student(NO,NAME,sex,classno,birth) VALUES(1,'zhangsan','1','gaosan1ban', '1950-10-12');
insert into t_student(name) values('wangwu'); //除name字段之外,剩下的所有字段自动插入NULL。 -
注意事项:
-
当一条insert语句执行成功之后,表格当中必然会多一行记录。即使多的这一行记录当中某些字段是NULL,后期也没有办法在执行insert语句插入数据了,只能使用update进行更新。
-
字段可以省略不写,但是后面的value对数量和顺序都有要求。
insert into t_student values(1,'jack','0','gaosan2ban','1986-10-23');
insert into t_student values(1,'jack','0','gaosan2ban');
-
一次插入多行数据:
insert into t_student (no,name,sex,classno,birth) values (3,'rose','1','gaosi2ban','1952-12-14'),(4,'laotie','1','gaosi2ban','1955-12-14');
-
-
将查询结果插入到一张表中:
- 当然插入表和查询结果形成的临时表的数据类型和字段要对应上。
-
语法格式:
update 表名 set 字段名1=值1,字段名2=值2... where 条件; //没有设置条件则将整张表数据全部更新(where被省略)。
-
实际案例:
- 将部门10的LOC修改为SHANGHAI,将部门名称修改为RENSHIBU。
- 更新所有的记录:
-
数据的删除:
- 语法格式:
delete from 表名 where 条件; //没有设置条件则将表中数据全部删除(where被省略)。
-
实际案例:
- 删除10部门数据?
- 删除所有的数据:
-
大型表的删除:
truncate table 表名; // 表被截断,不可回滚,永久丢失,效率比delete高。
-
表的删除:
drop table 表名; // 通用写法。 drop table if exists 表名; // oracle不支持这种写法。
十二、表结构的增删改
①添加字段:采用 alter table 来增加/删除/修改表结构,不影响表中的数据。
alter table 表名 add 字段名 数据类型;
-
实际举例:给t_student表添加email字段,数据类型为varchar(30)。
-
修改字段的数据类型:
alter table 表名 modify 字段名 数据类型;
- 实际举例:将t_student表的name字段长度减少为100。
-
修改字段的名称:
alter table 表名 change 旧字段名 新字段名 数据类型;
- 实际举例:将t_student表的sex字段名字改为gender。
alter table 表名 drop 字段名;
-
实际举例:删除t_student表的email字段。
十三、创建表加上约束
①非空约束_not null:先介绍一个知识:可以使用**ConSTRAINT [约束名]**来命名一个约束的,后面会用到。
-
非空约束,针对某个字段设置其值不为空,如:用户的姓名不能为空
-
唯一约束修饰的字段具有唯一性,不能重复。但可以为NULL。
-
实际举例:
- 给某一列添加unique:
drop table if exists t_user; create table t_user( id int, username varchar(255) unique // 列级约束 ); insert into t_user values(1,'zhangsan'); insert into t_user values(2,'zhangsan'); ERROR 1062 (23000): Duplicate entry 'zhangsan' for key 'username'
- 给两个列或者多个列添加unique:
drop table if exists t_user; create table t_user( id int, usercode varchar(255), username varchar(255), unique(usercode,username) // 多个字段联合起来添加1个约束unique 【表级约束】 //(usercode,username) 这一对的组合不能出现重复 ); insert into t_user values(1,'111','zs'); insert into t_user values(2,'111','ls'); insert into t_user values(3,'222','zs'); select * from t_user; insert into t_user values(4,'111','zs'); ERROR 1062 (23000): Duplicate entry '111-zs' for key 'usercode'drop table if exists t_user; create table t_user( id int, usercode varchar(255) unique, username varchar(255) unique //列级约束,各自都不能出现重复 ); insert into t_user values(1,'111','zs'); insert into t_user values(2,'111','ls'); ERROR 1062 (23000): Duplicate entry '111' for key 'usercode' -
注意:not null约束只有列级约束,没有表级约束。
-
如何查看约束?
use information_schema; select * from table_constraints where table_name = '表名'; //横着展示 //或者 select * from table_constraints where table_name = '表名'G //变成竖着展示
每个表应该具有主键,主键可以标识记录的唯一性,主键分为单一主键和复合(联合)主键,单一主键是由一个字段构成的,复合(联合)主键是由多个字段构成的。
-
主键的相关介绍:
- 主键相关的术语?
- 主键约束 : primary key
- 主键字段 : id字段添加primary key之后,id叫做主键字段。
- 主键值 : id字段中的每一个值都是主键值。
- 主键有什么作用?
- 表的设计三范式中有要求,第一范式就要求任何一张表都应该有主键。
- 主键的作用:主键值是这行记录在这张表当中的唯一标识。(就像一个人的身份证号码一样。)
- 主键的分类?
- 根据主键字段的字段数量来划分:
- 单一主键(推荐的,常用的。)
- 复合主键(多个字段联合起来添加一个主键约束)(复合主键不建议使用,因为复合主键违背三范式。)
- 根据主键性质来划分:
- 自然主键:主键值最好就是一个和业务没有任何关系的自然数。(这种方式是推荐的)
- 业务主键:主键值和系统的业务挂钩,例如:拿着银行卡的卡号做主键,拿着身份证号码作为主键。(不推荐用)最好不要拿着和业务挂钩的字段作为主键。因为以后的业务一旦发生改变的时候,主键值可能也需要随着发生变化,但有的时候没有办法变化,因为变化可能会导致主键值重复。
- 根据主键字段的字段数量来划分:
- 一张表的主键约束只能有一个。
- 主键相关的术语?
-
实际举例:
- 使用列级约束方式定义主键:
drop table if exists t_user; create table t_user( id int primary key, // 列级约束 username varchar(255), email varchar(255) ); insert into t_user(id,username,email) values(1,'zs','zs@123.com'); insert into t_user(id,username,email) values(2,'ls','ls@123.com'); insert into t_user(id,username,email) values(3,'ww','ww@123.com'); select * from t_user; insert into t_user(id,username,email) values(1,'jack','jack@123.com'); //ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY' insert into t_user(username,email) values('jack','jack@123.com'); //ERROR 1364 (HY000): Field 'id' doesn't have a default value-
根据以上的测试得出:id是主键,因为添加了主键约束,主键字段中的数据不能为NULL,也不能重复。
-
主键的特点:不能为NULL,也不能重复。
-
使用表级约束方式定义主键:
drop table if exists t_user; create table t_user( id int, username varchar(255), primary key(id) // 表级约束 ); insert into t_user(id,username) values(1,'zs'); insert into t_user(id,username) values(2,'ls'); insert into t_user(id,username) values(3,'ws'); insert into t_user(id,username) values(4,'cs'); select * from t_user; insert into t_user(id,username) values(4,'cx'); //ERROR 1062 (23000): Duplicate entry '4' for key 'PRIMARY'
- 复合主键(不推荐使用):
drop table if exists t_user; create table t_user( id int, username varchar(255), password varchar(255), primary key(id,username) ); insert .......
- MySQL提供主键值自增:
drop table if exists t_user; create table t_user( id int primary key auto_increment, // id字段自动维护一个自增的数字,从1开始,以1递增。 username varchar(255) ); insert into t_user(username) values('a'); insert into t_user(username) values('b'); insert into t_user(username) values('c'); insert into t_user(username) values('d'); insert into t_user(username) values('e'); insert into t_user(username) values('f'); select * from t_user;- 提示:Oracle当中也提供了一个自增机制——序列(sequence)对象。
外键主要是维护表之间的关系的,主要是为了保证参照完整性,如果表中的某个字段为外键字段,那么该字段的值必须来源于参照的表的主键,如:emp 中的 deptno 值必须来源于 dept表中的 deptno 字段值。
-
关于外键约束的相关术语:
- 外键约束:foreign key。
- 外键字段:添加有外键约束的字段。
-
外键值:外键字段中的每一个值。
-
实际案例:请设计数据库表,用来维护学生和班级的信息?
-
第一种方案:一张表存储所有数据。
no(主键) name classno classname 1 zs1 101 北京大兴区经济技术开发区亦庄二中高三1班 2 zs2 101 北京大兴区经济技术开发区亦庄二中高三1班 3 zs3 102 北京大兴区经济技术开发区亦庄二中高三2班 4 zs4 102 北京大兴区经济技术开发区亦庄二中高三2班 5 zs5 102 北京大兴区经济技术开发区亦庄二中高三2班 - 缺点:过于冗余,不推荐使用。
-
第二种方案:两张表(班级表和学生表)。
- t_class班级表:
cno(主键) cname 101 北京大兴区经济技术开发区亦庄二中高三1班 102 北京大兴区经济技术开发区亦庄二中高三2班 - t_student学生表:
sno(主键) sname classno(应添加外键约束) 1 zs1 101 2 zs2 101 3 zs3 102 4 zs4 102 5 zs5 102 -
根据第二种方案书写建表语言:
- t_student中的classno字段引用t_class表中的cno字段,故t_student表叫做子表,t_class表叫做父表。
- 顺序要求:
- 删除数据的时候,先删除子表,再删除父表。
- 添加数据的时候,先添加父表,在添加子表。
- 创建表的时候,先创建父表,再创建子表。
- 删除表的时候,先删除子表,在删除父表。
drop table if exists t_student; drop table if exists t_class; create table t_class( cno int, cname varchar(255), primary key(cno) ); create table t_student( sno int, sname varchar(255), classno int, primary key(sno), constraint student_class foreign key(classno) references t_class(cno)//给约束起一个别名 ); insert into t_class values(101,'xxxxxxxxxx'); insert into t_class values(102,'yyyyyyyyyy'); //这里使用xxxx和yyyy取代班级的名字是因为编码的问题,cmd窗口是GBK,但是我的MySQL是UTF8,所以中文会出一点问题,我也懒得改了! insert into t_student values(1,'zs1',101); insert into t_student values(2,'zs2',101); insert into t_student values(3,'zs3',102); insert into t_student values(4,'zs4',102); insert into t_student values(5,'zs5',102); insert into t_student values(6,'zs6',102); select * from t_class; select * from t_student;- 此时插入一个学生数据,给sno赋予一个未在t_class进行说明的数据,因为外键约束的关系,会报错。
insert into t_student values(7,'lisi',103);
-
-
其他注意事项:
-
外键值可以为NULL?
- 外键可以为NULL,以上面的数据为例设计一个案例。
- 这样会影响参照完整性,所以我们建议在表定义时将外键字段设置为非空。
-
外键字段引用其他表的某个字段的时候,被引用的字段必须是主键吗?
- 被引用的字段不一定是主键,但至少具有unique约束。
-
mysql 对有些约束的修改比较麻烦,所以我们可以先删除,再添加(以上面的t_student和t_class表为例)。
-
级联更新on update cascade:
//先删除外键约束 alter table t_student drop foreign key student_class; //再添加新的外键约束,加上级联更新 alter table t_student add constraint student_class foreign key(classno) references t_class(cno) on update cascade;
- 此时如果对父表t_class进行修改的话,t_student表中数据也会发生相应的修改。
update t_class set cno=100 where cname='xxxxxxxxxx';
-
级联删除on delete cascade:
//先删除外键约束 alter table t_student drop foreign key student_class; //再添加新的外键约束,加上级联删除 alter table t_student add constraint student_class foreign key(classno) references t_class(cno) on delete cascade;
- 此时如果对父表t_class进行删除的话,t_student表中数据也会发生相应的删除。
十四、存储引擎 ①什么是存储引擎?
- 存储引擎这个名字只有在MySQL中存在。(Oracle中有对应的机制,但是不叫做存储引擎。Oracle中没有特殊的名字,就是“表的存储方式”)
- MySQL支持很多存储引擎,每一个存储引擎都对应了一种不同的存储方式。每一个存储引擎都有自己的优缺点,需要在合适的时机选择合适的存储引擎。
-
数据库中的各表均被(在创建表时)指定的存储引擎来处理;在创建表时,可使用 ENGINE 选项为 CREATE TABLE语句显式指定存储引擎。
CREATE TABLE `表名` ( ...... ) ENGINE=InnoDB(存储引擎) DEFAULT CHARSET=utf8(字符集); //建表的时候可以指定存储引擎,也可以指定字符集。
- 如果在创建表时没有显式指定存储引擎,则该表使用当前默认的存储引擎;MySQL默认使用的存储引擎是InnoDB方式,默认采用的字符集是UTF8。
- 默认的存储引擎可在 my.ini 配置文件中使用 default-storage-engine 选项指定。
- 现有表的存储引擎可使用 ALTER TABLE 语句来改变:
ALTER TABLE TABLENAME ENGINE = INNODB;
- 为确定某表所使用的存储引擎,可以使用下面的语句:
SHOW CREATE TABLE 表名G SHOW TABLE STATUS LIKE '表名'G
-
服务器可用的引擎依赖于以下因素:MySQL 的版本、服务器在开发时如何被配置、启动选项。
-
查看当前MySQL支持的存储引擎:
show engines G
-
MyISAM存储引擎:
Engine: MyISAM Support: YES Comment: MyISAM storage engine Transactions: NO XA: NO Savepoints: NO- MyISAM这种存储引擎不支持事务。
- MyISAM是mysql最常用的存储引擎,但是这种引擎不是默认的。
- MyISAM采用三个文件组织一张表:
- xxx.frm(存储格式的文件)
- xxx.MYD(存储表中数据的文件)
- xxx.MYI(存储表中索引的文件)
- 优缺点:
- 优点:可被压缩,节省存储空间。并且可以转换为只读表,提高检索效率。
- 缺点:不支持事务。
-
InnoDB存储引擎:
Engine: InnoDB Support: DEFAULT Comment: Supports transactions, row-level locking, and foreign keys Transactions: YES XA: YES Savepoints: YES- 优点:支持事务、行级锁、外键等。这种存储引擎数据的安全得到保障。
- 表的结构存储在xxx.frm文件中。
- 数据存储在tablespace这样的表空间中(逻辑概念),无法被压缩,无法转换成只读。
- 这种InnoDB存储引擎在MySQL数据库崩溃之后提供自动恢复机制。
- InnoDB支持级联删除和级联更新。
-
MEMORY存储引擎:
Engine: MEMORY Support: YES Comment: Hash based, stored in memory, useful for temporary tables Transactions: NO XA: NO Savepoints: NO- 使用 MEMORY 存储引擎的表,其数据存储在内存中,且行的长度固定,这两个特点使得 MEMORY 存储引擎非常快。
- MEMORY 存储引擎管理的表具有下列特征:
- 在数据库目录内,每个表均以.frm 格式的文件表示。
- 表数据及索引被存储在内存中。
- 表级锁机制。
- 不能包含 TEXT 或 BLOB 字段。
- 优缺点:
- 缺点:不支持事务。数据容易丢失。因为所有数据和索引都是存储在内存当中的。
- 优点:查询速度最快。
- MEMORY 存储引擎以前被称为 HEAP 引擎。
- MyISAM 表最适合于大量的数据读而少量数据更新的混合操作。MyISAM 表的另一种
适用情形是使用压缩的只读表。 - 如果查询中包含较多的数据更新操作,应使用 InnoDB。其行级锁机制和多版本的支
持为数据读取和更新的混合操作提供了良好的并发机制。 - 可使用 MEMORY 存储引擎来存储非永久需要的数据,或者是能够从基于磁盘的表中
重新生成的数据。
十五、事务 ①基本介绍:
-
什么是事务?
- 一个事务是一个完整的业务逻辑单元,不可再分。
- 事件举例:银行账户转账,从A账户向B账户转账10000.需要执行两条update语句:
update t_act set balance = balance - 10000 where actno = 'act-001'; update t_act set balance = balance + 10000 where actno = 'act-002';
- 以上两条DML语句必须同时成功,或者同时失败,不允许出现一条成功,一条失败。要想保证以上的两条DML语句同时成功或者同时失败,那么就需要使用数据库的“事务机制”。
-
事务相关的语句只有:DML语句(insert、delete、update)
- 因为它们这三个语句都是和数据库表当中的“数据”相关的。事务的存在就是为了保证数据的完整性,安全性。
-
事务的特性:
- 原子性:事务是最小的工作单元,不可再分;整个事务中的所有操作,必须作为一个单元全部完成(或全部取消)。。
- 一致性:事务必须保证多条DML语句同时成功或者同时失败,在事务开始之前与结束之后,数据库都保持一致状态。。
- 隔离性:事务A与事务B之间具有隔离,一个事务不会影响其他事务的运行。。
- 持久性:持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束;在事务完成以后,该事务对数据库所作的更改将持久地保存在数据库之中,并不会被回滚。
-
事务中的一些概念:
- 事务(Transaction):一批操作(一组 DML)
- 开启事务(Start Transaction)
- 当执行DML 语句是其实就是开启一个事务。
- 回滚事务(rollback)
- 关于事务的回滚需要注意:只能回滚 insert、delete 和 update 语句,不能回滚 select(回滚select 没有任何意义),对于 create、drop、alter 这些无法回滚。
- 提交事务(commit)
- rollback,或者 commit 后事务就结束了。
- SET AUTOCOMMIT:禁用或启用事务的自动提交模式
-
MySQL事务默认情况下是自动提交的;只要执行任意一条DML(insert、delete、update)语句则提交一次。可以使用start transaction;关闭自动提交。
-
启动自动提交模式下:
- 如果自动提交模式被启用,则单条 DML 语句将缺省地开始一个新的事务。
- 如果该语句执行成功,事务将自动提交,并永久地保存该语句的执行结果;如果语句执行失败,事务将自动回滚,并取消该语句的结果。
- 在自动提交模式下,仍可使用 START TRANSACTION 语句来显式地启动事务;这时,一个事务仍可包含多条语句,直到这些语句被统一提交或回滚。
-
禁用自动提交模式下:
-
如果禁用自动提交,事务可以跨越多条语句;在这种情况下,事务可以用 COMMIT 和 ROLLBACK 语句来显式地提交或回滚。
-
自动提交模式可以通过服务器变量 AUTOCOMMIT 来控制:
SET AUTOCOMMIT = OFF; SET AUTOCOMMIT = ON; 或 SET SESSION AUTOCOMMIT = OFF; SET SESSION AUTOCOMMIT = ON;
- 查看AUTOCOMMIT变量的状态:
show variables like '%auto%';
-
事务的隔离级别决定了事务之间可见的级别。
-
当多个客户端并发地访问同一个表时,可能出现下面的一致性问题:
- 脏读取(Dirty Read):
- 一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交,这就出现了脏读取。
- 不可重复读(Non-repeatable Read):
- 在同一个事务中,同一个读操作对同一个数据的前后两次读取产生了不同的结果,这就
是不可重复读。
- 在同一个事务中,同一个读操作对同一个数据的前后两次读取产生了不同的结果,这就
- 幻像读(Phantom Read):
- 幻像读是指在同一个事务中以前没有的行,由于其他事务的提交而出现的新行。
- 脏读取(Dirty Read):
-
四个隔离级别:
- InnoDB 实现了四个隔离级别,用以控制事务所做的修改,并将修改通告至其它并发
的事务: - 读未提交(READ UMCOMMITTED):
- 允许一个事务可以看到其他事务未提交的数据。
- 存在脏读取(Dirty Read)现象。
- 读已提交(READ COMMITTED):
- 允许一个事务只能看到其他事务已经提交的修改,未提交的修改是不可见的。
- 解决了脏读取现象,但是存在不可重复读问题。
- 可重复读(REPEATABLE READ):
- 确保如果在一个事务中执行两次相同的 SELECT 语句,都能得到相同的结果,不管其他事务是否提交这些修改。 该隔离级别为 InnoDB 的缺省设置。
- 解决了不可重复读问题,但是存在幻象读现象。
- 串行化读/序列化读(SERIALIZABLE):
- 将一个事务与其他事务完全地隔离。
- 解决了所有问题,但是效率低,需要事务排队。
- Oracle数据库默认的隔离级别是:读已提交。MySQL数据库默认的隔离级别是:可重复读。
- InnoDB 实现了四个隔离级别,用以控制事务所做的修改,并将修改通告至其它并发
-
隔离级别与一致性问题的关系:
隔离级别 脏读取 不可重复读 幻象读 读未提交 可能 可能 可能 读已提交 不可能 可能 可能 可重复读 不可能 不可能 对InnDB不可能 串行化读 不可能 不可能 不可能
-
演示表格:
drop table if exists t_user; create table t_user( id int primary key auto_increment, username varchar(255) );
-
自动提交演示:
insert into t_user(username) values('zs'); select * from t_user; rollback; select * from t_user; -
禁用自动提交模式演示:
start transaction; insert into t_user(username) values('lisi'); select * from t_user; insert into t_user(username) values('wangwu'); select * from t_user; rollback; select * from t_user;start transaction; insert into t_user(username) values('wangwu'); insert into t_user(username) values('rose'); insert into t_user(username) values('jack'); select * from t_user; commit; select * from t_user; rollback; select * from t_user;
-
通过修改配置文件设置:
- 可以在 my.ini 文件中使用transaction-isolation 选项来设置服务器的缺省事务隔离级别。
- transaction-isolation 选项可以设置的值为:
读未提交 读已提交 可重复读 串行化读 READ-UNCOMMITTED READ-COMMITTED REPEATABLE-READ SERIALIZABLE -
通过命令动态设置隔离级别:
- 隔离级别也可以在运行的服务器中动态设置,应使用 SET TRANSACTION ISOLATION LEVEL 语句。
- 语法模式:
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL
- 其中
可以取值为:READ-UNCOMMITTED 、READ-COMMITTED 、REPEATABLE-READ、 SERIALIZABLE。
-
隔离级别的作用范围:
-
事务隔离级别的作用范围分为两种:全局级(对所有的会话有效)、会话级(只对当前的会话有效)。
-
实际举例:
- 设置会话级隔离级别为 READ COMMITTED :
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; 或: SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; //说明默认情况下作用范围为会话级
- 设置全局级隔离级别为 READ COMMITTED :
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
-
-
查看隔离级别:
-
服务器变量 tx_isolation(包括会话级和全局级两个变量)中保存着当前的会话隔离
级别。为了查看当前隔离级别,可访问 tx_isolation 变量: -
实际举例:
- 查看会话级的当前隔离级别:
SELECt @@tx_isolation; 或: SELECT @@session.tx_isolation;
- 查看全局级的当前隔离级别:
SELECT @@global.tx_isolation;
-
十六、索引 ①索引原理:
索引被用来快速找出在一个列上用一特定值的行。没有索引,MySQL 不得不首先以第一条记录开始,然后读完整个表直到它找出相关的行。表越大,花费时间越多。对于一个有序字段,可以运用二分查找(Binary Search),这就是为什么性能能得到本质上的提高。
MYISAM 和 INNODB 都是用 B+Tree 作为索引结构(主键,unique 都会默认的添加索引)
-
什么是索引?有什么用?
- 索引就相当于一本书的目录,通过目录可以快速的找到对应的资源;主键会自动添加索引,所以尽量根据主键查询效率较高。
- 在数据库方面,查询一张表的时候有两种检索方式:
- 第一种方式:全表扫描。
- 第二种方式:根据索引检索(效率很高)。
-
索引为什么可以提高检索效率呢?
- 其实最根本的原理是缩小了扫描的范围。
- 索引虽然可以提高检索效率,但是不能随意的添加索引,因为索引也是数据库当中的对象,也需要数据库不断的维护。是有维护成本的。比如,表中的数据经常被修改这样就不适合添加索引,因为数据一旦修改,索引需要重新排序,进行维护。
- 添加索引是给某一个字段,或者说某些字段添加索引。
select ename,sal from emp where ename = 'SMITH';
- 当ename字段上没有添加索引的时候,以上sql语句会进行全表扫描,扫描ename字段中所有的值。
- 当ename字段上添加索引的时候,以上sql语句会根据索引扫描,快速定位。
-
什么时候需要给字段添加索引?
- 表中该字段中的数据量庞大。
- 经常被检索,经常出现在where 子句中的字段。
- 经常被DML(insert、delete、update)操作的字段不建议添加索引,因为字段进行修改操作,索引也需要维护。
-
创建索引对象:
create index 索引名称 on 表名(字段名);
-
删除索引对象:
drop index 索引名称 on 表名;
-
查看索引:
show index from 表名;
-
查看sql语句的执行计划:
explain sql语句;
-
案例举例:查看薪资大于1500的员工名字和薪资情况。
//查看当前sql语句的执行计划 explain select ename,sal from emp where sal>1500;
//创建索引 create index emp_sal_index on emp(sal);
//再次查看当前sql语句的执行计划 explain select ename,sal from emp where sal>1500;
- 单一索引:给单个字段添加索引。
- 复合索引:给多个字段联合起来添加1个索引。
- 主键索引:主键上会自动添加索引。
- 唯一索引:有unique约束的字段上会自动添加索引。
select ename from emp where ename like '%A%';
- 模糊查询的时候,第一个通配符使用的是%,这个时候索引是失效的。
十七、视图 ①视图的基本介绍:
-
什么是视图?
- 站在不同的角度去看到数据。(同一张表的数据,通过不同的角度去看待)。
- 视图是一种根据查询(也就是 SELECt 表达式)定义的数据库对象,用于获取想要看到和使用的局部数据。
- 视图有时也被称为“虚拟表”。
- 视图可以被用来从常规表(称为“基表”)或其他视图中查询数据。
- 相对于从基表中直接获取数据,视图有以下好处:
- 访问数据变得简单。
- 可被用来对不同用户显示不同的表的内容。
-
视图的作用:
- 提高检索效率;隐藏表的实现细节(面向视图检索)。
- 用来协助适配表的结构以适应前端现有的应用程序。
-
视图的创建:
create view 视图名 as select语句; //只有DQL语句才能以视图对象的方式创建出来;DQL(数据查询语言)凡是select语句都是DQL。
- 注意:MySQL不支持子查询创建视图。
-
视图的删除:
drop view 视图名;
-
视图的修改:
alter view 视图名 as select语句;
-
对视图进行增删改查,会影响到原表数据。(通过视图影响原表数据的,不是直接操作的原表)
-
实际举例:
mysql> create table emp_test as select* from emp; Query OK, 14 rows affected (0.04 sec) Records: 14 Duplicates: 0 Warnings: 0 mysql> select* from emp_test; +-------+--------+-----------+------+------------+---------+---------+--------+ | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | +-------+--------+-----------+------+------------+---------+---------+--------+ | 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 | | 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 | | 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 | | 7566 | JonES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 | | 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | | 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 | | 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | | 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | | 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 | | 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | | 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 | | 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 | | 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | | 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 | +-------+--------+-----------+------+------------+---------+---------+--------+ 14 rows in set (0.00 sec) mysql> create view myview as -> select empno,ename,sal from emp_test; Query OK, 0 rows affected (0.01 sec) mysql> select* from myview; +-------+--------+---------+ | empno | ename | sal | +-------+--------+---------+ | 7369 | SMITH | 800.00 | | 7499 | ALLEN | 1600.00 | | 7521 | WARD | 1250.00 | | 7566 | JonES | 2975.00 | | 7654 | MARTIN | 1250.00 | | 7698 | BLAKE | 2850.00 | | 7782 | CLARK | 2450.00 | | 7788 | SCOTT | 3000.00 | | 7839 | KING | 5000.00 | | 7844 | TURNER | 1500.00 | | 7876 | ADAMS | 1100.00 | | 7900 | JAMES | 950.00 | | 7902 | FORD | 3000.00 | | 7934 | MILLER | 1300.00 | +-------+--------+---------+ 14 rows in set (0.01 sec) //通过视图修改原表数据: mysql> update myview set ename='Tom',sal=100 -> where empno=7369; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select* from myview; +-------+--------+---------+ | empno | ename | sal | +-------+--------+---------+ | 7369 | Tom | 100.00 | | 7499 | ALLEN | 1600.00 | | 7521 | WARD | 1250.00 | | 7566 | JonES | 2975.00 | | 7654 | MARTIN | 1250.00 | | 7698 | BLAKE | 2850.00 | | 7782 | CLARK | 2450.00 | | 7788 | SCOTT | 3000.00 | | 7839 | KING | 5000.00 | | 7844 | TURNER | 1500.00 | | 7876 | ADAMS | 1100.00 | | 7900 | JAMES | 950.00 | | 7902 | FORD | 3000.00 | | 7934 | MILLER | 1300.00 | +-------+--------+---------+ 14 rows in set (0.00 sec) mysql> select* from emp_test; +-------+--------+-----------+------+------------+---------+---------+--------+ | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | +-------+--------+-----------+------+------------+---------+---------+--------+ | 7369 | Tom | CLERK | 7902 | 1980-12-17 | 100.00 | NULL | 20 | | 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 | | 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 | | 7566 | JonES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 | | 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | | 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 | | 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | | 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | | 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 | | 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | | 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 | | 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 | | 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | | 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 | +-------+--------+-----------+------+------------+---------+---------+--------+ 14 rows in set (0.00 sec) //通过视图删除原表数据: mysql> delete from myview where empno=7369; Query OK, 1 row affected (0.01 sec) mysql> select* from myview; +-------+--------+---------+ | empno | ename | sal | +-------+--------+---------+ | 7499 | ALLEN | 1600.00 | | 7521 | WARD | 1250.00 | | 7566 | JonES | 2975.00 | | 7654 | MARTIN | 1250.00 | | 7698 | BLAKE | 2850.00 | | 7782 | CLARK | 2450.00 | | 7788 | SCOTT | 3000.00 | | 7839 | KING | 5000.00 | | 7844 | TURNER | 1500.00 | | 7876 | ADAMS | 1100.00 | | 7900 | JAMES | 950.00 | | 7902 | FORD | 3000.00 | | 7934 | MILLER | 1300.00 | +-------+--------+---------+ 13 rows in set (0.00 sec) mysql> select* from emp_test; +-------+--------+-----------+------+------------+---------+---------+--------+ | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | +-------+--------+-----------+------+------------+---------+---------+--------+ | 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 | | 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 | | 7566 | JonES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 | | 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | | 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 | | 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | | 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | | 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 | | 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | | 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 | | 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 | | 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | | 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 | +-------+--------+-----------+------+------------+---------+---------+--------+ 13 rows in set (0.00 sec)
十八、DBA命令 ①将数据库中的数据导出:
-
导出整个库(在Windows的Dos命令窗口中执行):
mysqldump 数据库名>存储位置 -uroot -p密码
-
导出指定数据库当中的指定表(在Windows的Dos命令窗口中执行):
mysqldump 数据库名 表名>存储位置 -uroot -p密码
-
登录 MYSQL 数据库管理系统之后执行:
source sql脚本
- 实际演示:
//创建一个新的数据库 mysql> create database demo; Query OK, 1 row affected (0.00 sec) //使用该数据库 mysql> use demo; Database changed //导入数据 mysql> source D:test.sql; Outfile disabled. ERROR: Failed to open file 'D:est.sql', error: 2 //这里文件路径的书写有点门道,按照windows的习惯书写的话,比如我上面的t就被认为是t转义字符了,无法正常执行。解决的方法就是再加上一个,\表示的就是‘’字符了,还有一种解决方法就是使用‘/’就可以正确表示了! mysql> source D:\test.sql; ERROR: Unknown command '\'. Query OK, 0 rows affected (0.00 sec) ...... mysql> show tables; +----------------+ | Tables_in_demo | +----------------+ | dept | | emp | | emp_test | | myview | | salgrade | | t_class | | t_student | | t_user | +----------------+ 8 rows in set (0.00 sec)
十九、数据库设计三范式 ①什么是设计范式?
- 设计表的依据;按照这个三范式设计的表不会出现数据冗余。
-
第一范式:数据库表中不能出现重复记录,每个字段是原子性的不能再分。
- 不符合第一范式的实际举例:
学生编号 学生姓名 联系方式 001 张三 zs@gmail.com,1359999999 002 李四 ls@gmail.com,13699999999 001 王五 ww@163.com,13488888888 - 存在的问题:
- 最后一条记录和第一条重复(不唯一,没有主键);联系方式字段可以再分,不是原子性的。
- 改进之后:
学生编号 学生姓名 Email 联系电话 001 张三 zs@gmail.com 1359999999 002 李四 ls@gmail.com 13699999999 003 王五 ww@163.com 13488888888 - 关于第一范式,每一行必须唯一,也就是每个表必须有主键,这是我们数据库设计的最基本要求,主要通常采用数值型或定长字符串表示,关于列不可再分,应该根据具体的情况来决定。如联系方式,为了开发上的便利行可能就采用一个字段了。
-
第二范式:第二范式是建立在第一范式基础上的,另外要求所有非主键字段完全依赖主键,不能产生部分依赖。
- 不符合第二范式的实际举例:
学生编号(主键) 学生姓名 教师编号(主键) 教师姓名 001 张三 001 王老师 002 李四 002 赵老师 003 王五 001 王老师 001 张三 002 赵老师 -
以上虽然确定了主键,但此表会出现大量的冗余,主要涉及到的冗余字段为“学生姓名”和“教师姓名”,出现冗余的原因在于,学生姓名部分依赖了主键的一个字段学生编号,而没有依赖教师编号,而教师姓名部门依赖了主键的一个字段教师编号,这就是第二范式部分依赖。
-
解决方案:分割为两个表格。
- 学生信息表:
学生编号(主键) 学生姓名 001 张三 002 李四 003 王五 - 教师信息表:
教师编号(主键) 教师姓名 001 王老师 002 赵老师 - 学生_老师关系表:
学生编号(主键)(外键为学生表的学生编号) 教师编号(主键)(外键为教师表的教师编号) 001 001 002 002 003 001 001 002 -
以上是一种典型的“多对多”的设计。
-
第三范式:建立在第二范式基础上的,非主键字段不能传递依赖于主键字段。(不要产生传递依赖)
- 不符合第三范式的实际举例:
学生编号(主键) 学生姓名 班级编号 班级名称 001 张三 01 一年一班 002 李四 02 一年二班 003 王五 03 一年三班 004 马六 03 一年三班 -
从上表可以看出,班级名称字段存在冗余,因为班级名称字段没有直接依赖于主键,班级名称字段依赖于班级编号,班级编号依赖于学生编号,那么这就是传递依赖。
-
解决方案:将冗余字段单独拿出来建立表。
- 学生信息表:
学生编号(主键) 学生姓名 班级编号(外键) 001 张三 01 002 李四 02 003 王五 03 004 马六 03 - 班级信息表:
班级编号(主键) 班级名称 01 一年一班 02 一年二班 03 一年三班 -
以上设计是一种典型的一对多的设计,一存储在一张表中,多存储在一张表中,在多的那张表中添加外键指向一的一方的主键。
| 范式 | 介绍 |
|---|---|
| 第一范式 | 有主键,具有原子性,字段不可分割。 |
| 第二范式 | 完全依赖,没有部分依赖。 |
| 第三范式 | 没有传递依赖。 |
- 数据库设计尽量遵循三范式,但是还是根据实际情况进行取舍,有时可能会拿冗余换速度,最终用目的要满足客户需求。
END
个人总结:
- 进行这一段MySQL的学习历程的原因是之前学习在学校学习过 『数据库概论』,在课堂上使用的是 Sql Server,很多公司使用MySQL,市面上的大多数教程也多是MySQL,而且学校学习偏向理论,注重底层逻辑的理解;所以想学习一下。
- 借助的教学资料是哔哩哔哩上面黑马的教学视频(在这里感谢黑马!):MySQL基础入门到精通视频教程-MySQL数据库实战;因为有学习过理论的基础:
- 所以我并没有通过视频进行学习,而是通过这个视频的配套资料进行笔记的编写,理解不通顺的地方再去看看视频怎么讲解的。
- 然后就把这个教程给整完了!
- 接下来讲讲自己对于这门教程的个人感受吧!首先就是培训机构的教程通病,过于功利性,很多东西都是浮于表面的使用,底层的机制没有讲清楚;但是因为我在学校学过这些底层的设计构建,所以能更好的构建自己的知识网络,结合一下就很好了!所以看到这一篇笔记的你们,不要止步于此,多多看看其他的数据库相关的书籍,多听百家之言,不要麻痹于这些流于表面的使用而沾沾自喜,在行业内是无法真正站住脚的!
Over!



