MySQL基础入门【3】
文章目录
- 13 补充知识,查询结果的去重
- 14 连接查询
- 14.1 什么是连接查询?
- 14.2 连接查询的分类?
- 14.3 基础知识
- 补充,表的别名
- 14.4 内连接
- 等值连接
- 非等值连接
- 自连接
- 14.5 外连接
- 14.6 三张表怎么连接查询?
- 15 子查询
- 15.1 什么是子查询?子查询都可以出现在哪里?
- 15.2 where 子句中使用子查询
- 15.3 from后面嵌套子查询
- 15.4 在select后面嵌套子查询
- 16 union
- 16.2 规则
- 17 limit (重要!)
- 17.1 语法机制
- 17.2 sql的分页机制
- 17.3 limit offset
- 18 完整的SQL语句补充
- 19 创建表
- 19.1 语法格式
- 19.3 MySQL中的数据类型
- char和varchar怎么选择?
- BLOB和CLOB类型的使用?
- 19.4 创建学生表
- 19.5 删除表 (补充内容,不想改大目录了)
- 20 向表中插入数据
- 20.1语法格式
- 20.2 示例
- 21 表的复制
- 22 修改数据
- 22.1 语法格式
- 23 删除数据
- 24 修改表
- 25 约束
- 25.1约束分类
- 25.2 not null
- 25.3 unique
- 25.4 PK
- 25.5 FK
- 26 级联更新与级联删除
- 26.1 on update cascode;
- 26.2 on delete cascade
- 27 存储引擎
- 27.1 完整的建表语句
- 27.2 什么是存储引擎呢?
- 27.3 当前mysql支持的存储引擎
- 27.4 常见的存储引擎
- MyISAM
- InnoDB
- MEMORY
- 28 事务
- 28.1 概述
- 28.2 事务的提交与回滚演示
- 28.3 自动提交模式
- 28.4 隔离级别
- 如何设置隔离级别
- 29 索引
- 29.1 使用索引
- 30 视图
- 30.1 什么是视图
- 30.2 创建视图
- 30.3 修改视图
- 30.4 更新视图
- 30.5 删除视图
MySQL下载请查看:MySQL基础入门【1】下载与使用
Part1笔记:MySQL基础入门【2】
动力节点入门视频链接:MySQL基础入门-mysql教程-数据库实战(MySQL基础+MySQL高级+MySQL优化+MySQL34道作业题)
数据及笔记下载链接:百度云链接
提取码:0r3s
13 补充知识,查询结果的去重
select distinct * from * ;
mysql> select distinct job from emp;
+-----------+
| job |
+-----------+
| CLERK |
| SALESMAN |
| MANAGER |
| ANALYST |
| PRESIDENT |
+-----------+
5 rows in set (0.01 sec)
只能出现在所有字段的最前面,对后面的所有字段进行联合去重。
mysql> select distinct deptno,job from emp;
+--------+-----------+
| deptno | job |
+--------+-----------+
| 20 | CLERK |
| 30 | SALESMAN |
| 20 | MANAGER |
| 30 | MANAGER |
| 10 | MANAGER |
| 20 | ANALYST |
| 10 | PRESIDENT |
| 30 | CLERK |
| 10 | CLERK |
+--------+-----------+
9 rows in set (0.00 sec)
test:统计岗位的数量?
mysql> select count(distinct job) from emp;
+---------------------+
| count(distinct job) |
+---------------------+
| 5 |
+---------------------+
1 row in set (0.00 sec)
14 连接查询
14.1 什么是连接查询?
在实际开发中,一般一个业务都会对应多张表,比如:学生和班级,起码两张表。
stuno stuname classno classname
1 zs 1 北京大兴区亦庄经济技术开发区第二中学高三1班
2 ls 1 北京大兴区亦庄经济技术开发区第二中学高三1班
…
学生和班级信息存储到一张表中,结果就像上面一样,数据会存在大量的重复,导致数据的冗余。
14.2 连接查询的分类?
1.根据语法出现的年代来划分的话,包括:
SQL92(一些老的DBA可能还在使用这种语法。DBA:DataBase Administrator,数据库管理员)
SQL99(比较新的语法)
2.根据表的连接方式来划分,包括:
内连接:
等值连接
非等值连接
自连接
外连接:
左外连接(左连接)
右外连接(右连接)
全连接(这个不讲,很少用!)
14.3 基础知识
在表的连接查询方面有一种现象,被称为:笛卡尔积现象。(笛卡尔积现象)
案例:找出每一个员工的部门名称,要求显示员工名和部门名。
EMP表中只有ename
+--------+--------+
| ename | deptno |
+--------+--------+
| SMITH | 20 |
| ALLEN | 30 |
| WARD | 30 |
| JONES | 20 |
| MARTIN | 30 |
| BLAKE | 30 |
| CLARK | 10 |
| SCOTT | 20 |
| KING | 10 |
| TURNER | 30 |
| ADAMS | 20 |
| JAMES | 30 |
| FORD | 20 |
| MILLER | 10 |
+--------+--------+
DEPT表
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
如果我们使用select ename,dname from emp,dept;
会得到56条记录,称为笛卡尔积现象,即对多个表进行联合查询时,如果没有任何的约束条件,则得到的查询结果数是多个表数据条数的乘积。
mysql> select ename,dname from emp,dept;
.......
56 rows in set (0.00 sec)
怎么避免笛卡尔积现象?
加过滤
思考:避免了笛卡尔积现象,会减少记录的匹配次数吗?
不会,次数还是56次。只不过显示的是有效记录。
补充,表的别名
select e.ename, d.dname from emp e, dept d;
第一,执行效率高(因为查询的字段可能会同时存在多个表中,这样更好区分);第二,可读性效果好。
查询每个员工的部门名称,要求显示员工名和部门名。
select e.ename, d.dname from emp e, dept d where e.deptno = d.deptno order by dname asc;
## SQL92 不用了
+--------+------------+
| ename | dname |
+--------+------------+
| CLARK | ACCOUNTING |
| KING | ACCOUNTING |
| MILLER | ACCOUNTING |
| SMITH | RESEARCH |
| JONES | RESEARCH |
| SCOTT | RESEARCH |
| ADAMS | RESEARCH |
| FORD | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| MARTIN | SALES |
| BLAKE | SALES |
| TURNER | SALES |
| JAMES | SALES |
+--------+------------+
14 rows in set (0.00 sec)
14.4 内连接
等值连接
最大特点是条件是等量关系
案例:查询每个员工的部门名称,要求现实员工名和部门名。
SQL99,语法中避免了再次使用where条件,和之后的where条件分离了
mysql> select e.ename,d.dname-> from emp e-> (inner) join dept d-> on e.deptno = d.deptno;
//inner可以省略
+--------+------------+
| ename | dname |
+--------+------------+
| SMITH | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| JONES | RESEARCH |
| MARTIN | SALES |
| BLAKE | SALES |
| CLARK | ACCOUNTING |
| SCOTT | RESEARCH |
| KING | ACCOUNTING |
| TURNER | SALES |
| ADAMS | RESEARCH |
| JAMES | SALES |
| FORD | RESEARCH |
| MILLER | ACCOUNTING |
+--------+------------+
14 rows in set (0.00 sec)
inner可以省略的。
非等值连接
找出每个员工的工资等级,要求显示员工名、工资、工资等级。
mysql> select e.ename, e.sal ,s.grade -> from emp e -> join salgrade s-> on e.sal between s.losal and s.hisal;
+--------+---------+-------+
| ename | sal | grade |
+--------+---------+-------+
| SMITH | 800.00 | 1 |
| ALLEN | 1600.00 | 3 |
| WARD | 1250.00 | 2 |
| JONES | 2975.00 | 4 |
| MARTIN | 1250.00 | 2 |
| BLAKE | 2850.00 | 4 |
| CLARK | 2450.00 | 4 |
| SCOTT | 3000.00 | 4 |
| KING | 5000.00 | 5 |
| TURNER | 1500.00 | 3 |
| ADAMS | 1100.00 | 1 |
| JAMES | 950.00 | 1 |
| FORD | 3000.00 | 4 |
| MILLER | 1300.00 | 2 |
+--------+---------+-------+
14 rows in set (0.00 sec)
自连接
最大的特点是:一张表看做两张表。自己连接自己。
案例:找出每个员工的上级领导,要求显示员工名和对应的领导名。
select a.ename as 'worker', b.ename as 'leader' from emp a inner join emp b on a.mgr = b.empno;
//这里的as一定要,不然就会报错,毕竟出现了重名
//因为king没有上级,所以这里没有king的记录。
+--------+--------+
| worker | leader |
+--------+--------+
| SMITH | FORD |
| ALLEN | BLAKE |
| WARD | BLAKE |
| JONES | KING |
| MARTIN | BLAKE |
| BLAKE | KING |
| CLARK | KING |
| SCOTT | JONES |
| TURNER | BLAKE |
| ADAMS | SCOTT |
| JAMES | BLAKE |
| FORD | JONES |
| MILLER | CLARK |
+--------+--------+
14.5 外连接
外连接最重要的特点是:主表的数据无条件的全部查询出来。
一般在使用过程中,还是外连接的使用更多一些。至少可以保证数据的完整性。
内连接:
假设A和B表进行连接,使用内连接的话,凡是A表和B表能够匹配上的记录查询出来,这就是内连接。
AB两张表没有主副之分,两张表是平等的。
外连接:
假设A和B表进行连接,使用外连接的话,AB两张表中有一张表是主表,一张表是副表,主要查询主表中的数据,捎带着查询副表,当副表中的数据没有和主表中的数据匹配上,副表自动模拟出NULL与之匹配。
外连接的分类?
- 左外连接(左连接):表示左边的这张表是主表。
- 右外连接(右连接):表示右边的这张表是主表。
左连接有右连接的写法,右连接也会有对应的左连接的写法。
比如刚刚的那个案例,用外连接左连接的写法就应该是:
如果使用右连接就要改一下表的顺序。
mysql> select a.ename as '员工'-> , b.ename as '领导'-> from emp a-> left outer join-> emp b-> on -> a.mgr = b.empno;
+---------+--------+
| 员工 | 领导 |
+---------+--------+
| SMITH | FORD |
| ALLEN | BLAKE |
| WARD | BLAKE |
| JONES | KING |
| MARTIN | BLAKE |
| BLAKE | KING |
| CLARK | KING |
| SCOTT | JONES |
| KING | NULL |
| TURNER | BLAKE |
| ADAMS | SCOTT |
| JAMES | BLAKE |
| FORD | JONES |
| MILLER | CLARK |
+---------+--------+
14 rows in set (0.00 sec)
select a.ename as worker, b.ename as leader-> from emp a -> right outer join -> emp b-> on -> a.mgr = b.empno-> order by leader;
## outer也是可以省略的,因为毕竟有left和right
+--------+--------+
| worker | leader |
+--------+--------+
| NULL | ADAMS |
| NULL | ALLEN |
| JAMES | BLAKE |
| TURNER | BLAKE |
| MARTIN | BLAKE |
| WARD | BLAKE |
| ALLEN | BLAKE |
| MILLER | CLARK |
| SMITH | FORD |
| NULL | JAMES |
| FORD | JONES |
| SCOTT | JONES |
| CLARK | KING |
| BLAKE | KING |
| JONES | KING |
| NULL | MARTIN |
| NULL | MILLER |
| ADAMS | SCOTT |
| NULL | SMITH |
| NULL | TURNER |
| NULL | WARD |
+--------+--------+
21 rows in set (0.00 sec)
test:找出哪个部门没有员工。
select d.* from dept d left join emp e on d.deptno = e.deptno where e.ename is null;
## 这里的ename也可以换成其他别的empno
+--------+------------+--------+
| DEPTNO | DNAME | LOC |
+--------+------------+--------+
| 40 | OPERATIONS | BOSTON |
+--------+------------+--------+
1 row in set (0.01 sec)
这里如果只写d.dname应该是查不出来的。
14.6 三张表怎么连接查询?
example: 找出每一个员工的部门名称以及工资等级。
select e.ename, d.dname, s.grade-> from-> emp e-> join -> dept d-> on -> e.deptno = d.deptno-> join -> salgrade s-> on -> e.sal between s.losal and s.hisal;
提示:做SQL题最好分步进行
....AjoinBon...joinCon...表示:A表和B表先进行表连接,连接之后A表继续和C表进行连接。
Test:找出每一个员工的部门名称、工资等级、以及上级领导。
select e1.ename as '员工',d.dname,s.grade,e2.ename as '领导' -> from emp e1 -> left join emp e2-> on-> e1.mgr = b.empno-> join-> dept d-> on-> e1.deptno = d.deptno-> join-> salgrade s-> on -> e1.sal between s.losal and s.hisal;
+--------+------------+-------+--------+
| 员工 | dname | grade | 领导 |
+--------+------------+-------+--------+
| SMITH | RESEARCH | 1 | FORD |
| ALLEN | SALES | 3 | BLAKE |
| WARD | SALES | 2 | BLAKE |
| JONES | RESEARCH | 4 | KING |
| MARTIN | SALES | 2 | BLAKE |
| BLAKE | SALES | 4 | KING |
| CLARK | ACCOUNTING | 4 | KING |
| SCOTT | RESEARCH | 4 | JONES |
| KING | ACCOUNTING | 5 | NULL |
| TURNER | SALES | 3 | BLAKE |
| ADAMS | RESEARCH | 1 | SCOTT |
| JAMES | SALES | 1 | BLAKE |
| FORD | RESEARCH | 4 | JONES |
| MILLER | ACCOUNTING | 2 | CLARK |
+--------+------------+-------+--------+
15 子查询
15.1 什么是子查询?子查询都可以出现在哪里?
select语句当中嵌套select语句,被嵌套的select语句是子查询。
子查询可以出现在哪里?
select..(select).from..(select).where..(select).
15.2 where 子句中使用子查询
案例:找出高于平均薪资的员工信息。
select * from emp where sal > (select avg(sal) from emp);
+-------+-------+-----------+------+------------+---------+------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+-------+-----------+------+------------+---------+------+--------+
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 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 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
+-------+-------+-----------+------+------------+---------+------+--------+
6 rows in set (0.01 sec)
分步理解就是:
第一步:找出平均薪资;
第二步:where过滤;
15.3 from后面嵌套子查询
找出每个部门的平均薪水的薪资等级。
第一步:找出每个部门的平均薪水
mysql> select deptno,avg(sal)-> from emp -> group by deptno;
+--------+-------------+
| deptno | avg(sal) |
+--------+-------------+
| 20 | 2175.000000 |
| 30 | 1566.666667 |
| 10 | 2916.666667 |
+--------+-------------+
第二步:将刚刚查出来的表当作临时表t
select t.*,s.grade from (select deptno,avg(sal) as avgsal from emp group by deptno) t join salgrade s on t.avgsal between s.losal and s.hisal;
+--------+-------------+-------+
| deptno | avgsal | grade |
+--------+-------------+-------+
| 20 | 2175.000000 | 4 |
| 30 | 1566.666667 | 3 |
| 10 | 2916.666667 | 4 |
+--------+-------------+-------+
3 rows in set (0.00 sec)
另一题:找出每个部门平均的薪水等级。
第一步:找出每个员工的薪资等级及部门
select e.ename,e.deptno, s.grade-> from-> emp e-> join -> salgrade s-> on e.sal between s.losal and s.hisal;
+--------+--------+-------+
| ename | deptno | grade |
+--------+--------+-------+
| SMITH | 20 | 1 |
| ALLEN | 30 | 3 |
| WARD | 30 | 2 |
| JONES | 20 | 4 |
| MARTIN | 30 | 2 |
| BLAKE | 30 | 4 |
| CLARK | 10 | 4 |
| SCOTT | 20 | 4 |
| KING | 10 | 5 |
| TURNER | 30 | 3 |
| ADAMS | 20 | 1 |
| JAMES | 30 | 1 |
| FORD | 20 | 4 |
| MILLER | 10 | 2 |
+--------+--------+-------+
14 rows in set (0.00 sec)
将这一长段作为一个临时表 t,再分组选出平均值
select deptno,avg(grade) as avggradelevel
from
(select e.ename, e.deptno,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal) t
group by deptno
order by deptno;
+--------+---------------+
| deptno | avggradelevel |
+--------+---------------+
| 10 | 3.6667 |
| 20 | 2.8000 |
| 30 | 2.5000 |
+--------+---------------+
3 rows in set (0.01 sec)
啊啊啊啊但其实并不用这么复杂!!!!不需要子查询!!!!
我是笨蛋。
mysql> select e.deptno,avg(s.grade)-> from-> emp e-> join-> salgrade s-> on e.sal between s.losal and s.hisal-> group by -> e.deptno-> order by-> e.deptno;
+--------+--------------+
| deptno | avg(s.grade) |
+--------+--------------+
| 10 | 3.6667 |
| 20 | 2.8000 |
| 30 | 2.5000 |
+--------+--------------+
有一点没想明白的地方是,
(select e.ename, e.deptno,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal) t
这一句为什么可以直接省略了啊?以下就可以直接搜出deptno和对应的grade
我理解的是,应该是在这一步的查询,第一步执行的是join,直接将两张表连接成了一张表,然后再执行select
select e.deptno,s.grade-> from -> emp e-> join -> salgrade s-> on e.sal between s.losal and s.hisal;
+--------+-------+
| deptno | grade |
+--------+-------+
| 20 | 1 |
| 30 | 3 |
| 30 | 2 |
| 20 | 4 |
| 30 | 2 |
| 30 | 4 |
| 10 | 4 |
| 20 | 4 |
| 10 | 5 |
| 30 | 3 |
| 20 | 1 |
| 30 | 1 |
| 20 | 4 |
| 10 | 2 |
+--------+-------+
14 rows in set (0.00 sec)
15.4 在select后面嵌套子查询
找出每个员工所在的部门名称,要求显示员工名和部门名。
select e.ename, d.dname from emp e join dept d on e.deptno = d.deptno;
+--------+------------+
| ename | dname |
+--------+------------+
| SMITH | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| JONES | RESEARCH |
| MARTIN | SALES |
| BLAKE | SALES |
| CLARK | ACCOUNTING |
| SCOTT | RESEARCH |
| KING | ACCOUNTING |
| TURNER | SALES |
| ADAMS | RESEARCH |
| JAMES | SALES |
| FORD | RESEARCH |
| MILLER | ACCOUNTING |
+--------+------------+
14 rows in set (0.00 sec)
如果用子查询的话
select e.ename,(select d.dname from dept d where e.deptno = d.deptno) as dname
from emp e;
!执行的过程可以理解一下:
先看一下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)
先从emp表中得到第一条信息,比如这个人叫smith,工号是7369,这条信息被传入select d.dname from dept d where e.deptno = d.deptno
,这里的e.deptno
就是7369,然后通过这条查询,我们得到对应的名字是RESEARCH
.
16 union
可以将查询结果集相加
task:找出工作岗位是selesmen和manager的员工?
回顾:
select ename,job from emp where job = 'SALESMAN' or job = 'MANAGER';
select ename,job from emp where job in('SALESMAN', 'MANAGER');
+--------+----------+
| ename | job |
+--------+----------+
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| JONES | MANAGER |
| MARTIN | SALESMAN |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| TURNER | SALESMAN |
+--------+----------+
7 rows in set (0.00 sec)
使用union
:
select ename, job from emp where job = 'MANAGER'-> union-> select ename, job from emp where job = 'SALESMAN';
+--------+----------+
| ename | job |
+--------+----------+
| JONES | MANAGER |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| MARTIN | SALESMAN |
| TURNER | SALESMAN |
+--------+----------+
7 rows in set (0.00 sec)
得到的顺序不一样,但是很好理解。
可以把两张不相干的表中的数据拼接在一起显示,下面展示了一个毫无用的查询。
mysql> select ename from emp-> union-> select dname from dept;
+------------+
| ename |
+------------+
| SMITH |
| ALLEN |
| WARD |
| JONES |
| MARTIN |
| BLAKE |
| CLARK |
| SCOTT |
| KING |
| TURNER |
| ADAMS |
| JAMES |
| FORD |
| MILLER |
| ACCOUNTING |
| RESEARCH |
| SALES |
| OPERATIONS |
+------------+
16.2 规则
显示的列名是第一个查询结果的列名
union的两个查询结果的列数必须相等
17 limit (重要!)
以后分页查询靠它。
limit是mysql特有的,其他数据库中没有,不通用。(Oracle中有一个相同的机制,叫做rownum)
limit取结果集中的部分数据。
17.1 语法机制
limit startIndex, lengthstartIndex表示起始位置,从0开始,0表示第一条数据,不填的话默认为0。length表示取几个
取出工资前五的员工
select ename, sal from emp order by sal desc limit 5;
select ename, sal from emp order by sal desc limit 0,5;
+-------+---------+
| ename | sal |
+-------+---------+
| KING | 5000.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
找出工资排名在第4到第9名的员工?
select ename, sal from emp order by sal desc limit 3,6;
+--------+---------+
| ename | sal |
+--------+---------+
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| ALLEN | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
+--------+---------+
17.2 sql的分页机制
每页显示3条记录:使用limit
第1页:0, 3
第2页:3, 3
第3页:6, 3
第4页:9, 3
第5页:12, 3
公式:每页显示pageSize条记录:
第pageNo页:(pageNo - 1) * pageSize, pageSize
pageSize:是每页显示多少条记录
pageNo:第几页
java代码:
int pageNo = 2; #这里接收输入的页码数
int pageSize = 10;limit (pageNo - 1)* pageSize, pageSize
17.3 limit offset
offset n表示跳过x条语句
limit y offset x 分句表示查询结果跳过 x 条数据,读取前 y 条数据
找出工资排名
18 完整的SQL语句补充
select 5..from 1 ..where 2..group by 3..having 4..order by 6..limit 7..
19 创建表
概念回顾:
DQL(Data query language)(数据查询语言): 查询语句,凡是select语句都是DQL。
DML(Data manage language)(数据操作语言):insert delete update,对表当中的数据进行增删改。
DDL(Data Definition language)(数据定义语言):create drop alter,对表结构的增删改。
TCL(Task Control language)(事务控制语言):commit提交事务,rollback回滚事务。(TCL中的T是Transaction)
DCL (Data Control language)(数据控制语言): grant授权、revoke撤销权限等。用来定义数据库的访问权限和安全级别
这部分开始学习DML
19.1 语法格式
create table 表名(字段名1 数据类型,字段名2 数据类型,字段名3 数据类型,....);
19.3 MySQL中的数据类型
name | type |
---|---|
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。
BLOB和CLOB类型的使用?
电影表: t_movie
id(int) name(varchar) playtime(date/char) poster(BLOB) description(CLOB)
1 蜘蛛侠
2
3
BLOB和CLOB必须使用java io流才可以插入。
但在实际使用过程中,很少有人直接把大文件、视频放进去,但是可能有小图片(比如QQ头像)
19.4 创建学生表
表名在数据库当中一般建议以:t_ 或者tbl_开始。
学生信息包括:
学号、姓名、性别、班级编号、生日
学号:bigint
姓名:varchar
性别:char
班级编号:int
生日:char
create table t_student(id bigint,name varchar(255),sex char(1) default 1, # 修改了默认值,后面的查询没有修改, 默认值是0classno varchar(255),birth char(10));show tables;
+-----------------------+
| Tables_in_bjpowernode |
+-----------------------+
| DEPT |
| EMP |
| SALGRADE |
| t_student |
| t_user |
+-----------------------+desc t_student;
+---------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id | bigint | YES | | NULL | |
| name | varchar(255) | YES | | NULL | |
| sex | char(1) | YES | | NULL | |
| classno | varchar(255) | YES | | NULL | |
| birth | char(10) | YES | | NULL | |
+---------+--------------+------+-----+---------+-------+
19.5 删除表 (补充内容,不想改大目录了)
drop table <表名>;
//DROP TABLE用于删除一个或多个表。您必须有每个表的DROP权限。所有的表数据和表定义会被取消,所以使用本语句要小心!
drop table t_user2;
Query OK, 0 rows affected (0.01 sec)drop table xx;
ERROR 1051 (42S02): Unknown table 'bjpowernode.xx'//对于不存在的表,使用IF EXISTS用于防止错误发生。当使用IF EXISTS时,对于每个不存在的表,会生成一个NOTE(警告)。
drop table if exists xx;
Query OK, 0 rows affected, 1 warning (0.00 sec)
20 向表中插入数据
20.1语法格式
insert into 表名(字段名1,字段名2,字段名3,....) values(值1,值2,值3,....)
# 要求:字段的数量和值的数量相同,并且数据类型要对应相同。//报错:
insert into t_student(no,name,sex,classno,birth) values(1,'zhangsan','1','gaosan1ban');ERROR 1136 (21S01): Column count doesn't match value count at row 1
20.2 示例
insert into t_student(no,name,sex,classno,birth) values(1,'zhangsan','1','gaosan1ban', '1950-10-12');select * from t_student;+------+----------+------+------------+------------+| no | name | sex | classno | birth |+------+----------+------+------------+------------+| 1 | zhangsan | 1 | gaosan1ban | 1950-10-12 |+------+----------+------+------------+------------+
顺序不重要
insert into t_student(name,sex,classno,birth,no) values('lisi','1','gaosan1ban', '1950-10-12',2);mysql> select * from t_student;+------+----------+------+------------+------------+| no | name | sex | classno | birth |+------+----------+------+------------+------------+| 1 | zhangsan | 1 | gaosan1ban | 1950-10-12 || 2 | lisi | 1 | gaosan1ban | 1950-10-12 |+------+----------+------+------------+------------+
insert into t_student(name) values('wangwu'); # 除name字段之外,剩下的所有字段自动插入NULL。mysql> select * from t_student;+------+----------+------+------------+------------+| no | name | sex | classno | birth |+------+----------+------+------------+------------+| 1 | zhangsan | 1 | gaosan1ban | 1950-10-12 || 2 | lisi | 1 | gaosan1ban | 1950-10-12 || NULL | wangwu | NULL | NULL | NULL |+------+----------+------+------------+------------+
字段可以省略不写,但是后面的value对数量和顺序都有要求,必须严格按照定义的来:
insert into t_student values(1,'jack','0','gaosan2ban','1986-10-23');
mysql> select * from t_student;+------+----------+------+------------+------------+
| no | name | sex | classno | birth |
+------+----------+------+------------+------------+
| 1 | zhangsan | 1 | gaosan1ban | 1950-10-12 |
| 1 | jack | 0 | gaosan2ban | 1986-10-23 |
+------+----------+------+------------+------------+
一次插入多条数据
insert into t_student(no,name,sex,classno,birth) values(3,'rose','1','gaosi2ban','1952-12-14'),(4,'laotie','1','gaosi2ban','1955-12-14');select * from t_student;
+------+----------+------+------------+------------+
| no | name | sex | classno | birth |
+------+----------+------+------------+------------+
| 1 | zhangsan | 1 | gaosan1ban | 1950-10-12 |
| 1 | jack | 0 | gaosan2ban | 1986-10-23 |
| 3 | rose | 1 | gaosi2ban | 1952-12-14 |
| 4 | laotie | 1 | gaosi2ban | 1955-12-14 |
+------+----------+------+------------+------------+
21 表的复制
语法:
create table t_xxx as select xxx from t_xxx;
# 将查询结果当做表创建出来。
create table emp1 as select * from emp;select * from emp1;
+-------+--------+-----------+------+------------+---------+---------+--------+
| 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 |
+-------+--------+-----------+------+------------+---------+---------+--------+
将查询结果插入到一张表中?
create table dept1 as select * from dept;insert into dept1 select * from dept;select * from dept1;+--------+------------+----------+| DEPTNO | DNAME | LOC |+--------+------------+----------+| 10 | ACCOUNTING | NEW YORK || 20 | RESEARCH | DALLAS || 30 | SALES | CHICAGO || 40 | OPERATIONS | BOSTON || 10 | ACCOUNTING | NEW YORK || 20 | RESEARCH | DALLAS || 30 | SALES | CHICAGO || 40 | OPERATIONS | BOSTON |+--------+------------+----------+
22 修改数据
22.1 语法格式
update 表名 set 字段名1=值1,字段名2=值2... where 条件;
#没有where则全部更新
案例:将部门10的LOC修改为SHANGHAI,将部门名称修改为RENSHIBU
update dept1 set DNAME = 'RENSHIBU', LOC='SHANGHAI' where deptno = 10;select * from dept1;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | RENSHIBU | SHANGHAI |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
| 10 | RENSHIBU | SHANGHAI |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
更新所有记录
update dept1 set loc = 'x', dname = 'y';mysql> select * from dept1;+--------+-------+------+| DEPTNO | DNAME | LOC |+--------+-------+------+| 10 | y | x || 20 | y | x || 30 | y | x || 40 | y | x || 10 | y | x || 20 | y | x || 30 | y | x || 40 | y | x |+--------+-------+------+
23 删除数据
语法格式
delete from 表名 where 条件;
#没有where就删库跑路了
删除10部门数据?
delete from dept1 where deptno = 10;mysql> select * from dept1;
+--------+-------+------+
| DEPTNO | DNAME | LOC |
+--------+-------+------+
| 20 | y | x |
| 30 | y | x |
| 40 | y | x |
| 20 | y | x |
| 30 | y | x |
| 40 | y | x |
+--------+-------+------+
6 rows in set (0.00 sec)
删除所有记录?
delete from dept1;
怎么删除大型表
数据量大的表删除比较耗时,使用delete需要几个小时也很正常,因为它没有释放数据的真实存储空间,还有后悔的机会。
truncate table 表名; // 表被截断,不可回滚。永久丢失。风险系数高!truncate emp1;
Query OK, 0 rows affected (0.02 sec)mysql> select * from emp1;
Empty set (0.00 sec)########################
create table emp2 as select * from emp;
Query OK, 14 rows affected, 2 warnings (0.01 sec)
Records: 14 Duplicates: 0 Warnings: 2mysql> delete from emp2;
Query OK, 14 rows affected (0.00 sec)mysql> select * from emp2;
Empty set (0.00 sec)
增删改查有一个术语:CRUD操作
Create(增) Retrieve(检索) Update(修改) Delete(删除)
24 修改表
对于表结构的修改,这里不讲了,大家使用工具完成即可,因为在实际开发中表一旦设计好之后,对表结构的修改是很少的,修改表结构就是对之前的设计进行了否定,即使需要修改表结构,我们也可以直接使用工具操作。修改表结构的语句不会出现在Java代码当中。
出现在java代码当中的sql包括:insert delete update select(这些都是表中的数据操作。)
25 约束
在创建表的时候,可以给表的字段添加相应的约束,添加约束的目的是为了保证表中数据的合法性、有效性、完整性。
25.1约束分类
非空约束(not null):约束的字段不能为NULL
唯一约束(unique):约束的字段不能重复
主键约束(primary key):约束的字段既不能为NULL,也不能重复(简称PK)
外键约束(foreign key):…(简称FK)
检查约束(check):注意Oracle数据库有check约束,但是mysql没有,目前mysql不支持该约束。
25.2 not null
drop table if exists t_user;
create table t_user(
id int,
username varchar(255) not null,
password varchar(255));insert into t_user(id,password) values(1,'123'); //编译错误,约束username字段不能为空!
# ERROR 1364 (HY000): Field 'username' doesn't have a default valueinsert into t_user(id,username,password) values(1,'lisi','123');desc t_user;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| username | varchar(255) | YES | UNI | NULL | |
| passpord | varchar(255) | NO | | NULL | |
+----------+--------------+------+-----+---------+-------+
25.3 unique
唯一性约束修饰的字段具有唯一性,不能重复。但可以为null。
NULL不是值,在上一小节测试过了。
给两个列或者多个列添加unique
create table t_user(id int,usercode varchar(255),username varchar(255),unique(usercode,username) #多个字段联合起来添加一个约束unique 【表级约束】);
insert into t_user2 values(1,'111','zs');insert into t_user2 values(2,'111','ls');
Query OK, 1 row affected (0.00 sec)insert into t_user2 values(4,'111','zs');
ERROR 1062 (23000): Duplicate entry '111-zs' for key 't_user2.usercode'
25.4 PK
怎么给一张表添加主键约束?
drop table if exists t_student;create table t_student(-> student_id int(10) primary key,-> student_name varchar(20) not null,-> sex char(2) default 'm',-> birthday date,-> email varchar(30),-> classes_id int(3)-> );desc t_student;
+--------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| student_id | int | NO | PRI | NULL | |
| student_name | varchar(20) | NO | | NULL | |
| sex | char(2) | YES | | m | |
| birthday | date | YES | | NULL | |
| email | varchar(30) | YES | | NULL | |
| classes_id | int | YES | | NULL | |
+--------------+-------------+------+-----+---------+-------+insert into t_student values(1001, 'zhangsan','m','1988-01-01','qqq@163.com',10);
也可以通过表级约束为约束起个名称:
drop table if exists t_student;
create table t_student(student_id int(10),student_name varchar(20) not null,sex char(2) default 'm',birthday date, email varchar(30) ,classes_id int(3),CONSTRAINT p_id PRIMARY key (student_id)
)
主键相关的术语?
主键约束 :primary key
主键字段 : id字段添加primary key之后,id叫做主键字段
主键值 :id字段中的每一个值都是主键值。
主键有什么作用?
根据主键字段的字段数量来划分:
单一主键 (推荐的,常用的。
复合主键(多个字段联合起来添加一个主键约束) (复合主键不建议使用,因为复合主键违背三范式。)
根据主键性质来划分:
自然主键 :主键值最好就是一个和业务没有任何关系的自然数。(这种方式是推荐的)
业务主键 : 主键值和系统的业务挂钩,例如:拿着银行卡的卡号做主键、拿着身份证号做为主键。(不推荐使用)
最好不要拿着和业务挂钩的字段做为主键。因为以后的业务一旦发生改变的时候,主键也可能需要随着发生变化,但有的时候没有办法变化,因为变化可能会导致主键重复。
一个表的主键约束只能有一个。
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');
select * from t_user;
+----+----------+
| id | username |
+----+----------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+----------+
提示:Oracle当中也提供了一个自增机制,叫做:序列(sequence)对象。
25.5 FK
外键主要是维护表与表之间的关系的,主要是为了保证参照完整性,如果表中的某个字段为外键字段,那么该字段的值必须来源于参照的表的具有unique约束的字段。如:emp中的deptno值必须来源于dept的deptno字段值。
建学生和班级表之间的连接:
#建立班级表
create table t_classes(-> classes_id int(3),-> classes_name varchar(40),-> constraint pk_classes_id primary key(classes_id)-> );
#建立学生表并加入外键约束
create table t_student(-> student_id int(10),-> student_name varchar(20),-> sex char(2),-> birthday date,-> email varchar(30),-> classes_id int(3),-> constraint student_id_pk primary key(student_id),-> constraint fk_classes_id foreign key(classes_id) references t_classes(classes_id)-> );#加入一个学生,失败了
insert into t_student values(1001,'zhangsan','m','1988-01-10','qqq@123.com',10);
#ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`bjpowernode`.`t_student`, CONSTRAINT `fk_classes_id` FOREIGN KEY (`classes_id`) REFERENCES `t_classes` (`classes_id`))
因为在班级表中不存在班级编号为10的班级,外键约束起到了作用,存在外键的表就是子表,参照的表就是父表。建议将外键字段设置为非空。
删除数据的时候,先删除子表,再删除父表。
添加数据的时候,先添加父表,再添加子表。
创建表的时候,先创建父表,再创建子表。
删除表的时候,先删除子表,再删除父表
当子表中存在有父表的引用记录时,删除或者修改复表的数据会出现报错:
# 先添加数据到班级表
insert into t_classes values(10,'366');# 再插入数据到学生表
insert into t_student values(1001,'zhangsan','m','1998-01-01','qqq@163.com',10);# 尝试修改班级表中的班级10为20报错
update t_classes set classes_id = 20 where classes_name = '366';
# ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`bjpowernode`.`t_student`, CONSTRAINT `fk_classes_id` FOREIGN KEY (`classes_id`) REFERENCES `t_classes` (`classes_id`))# 正确做法应该是,先删除子表中的数据,再对父表中的数据进行修改,或者我们也可以通过下一节的级联删除进行。
26 级联更新与级联删除
mysql对有些约束的修改比较麻烦,所以我们可以先删除,再添加
好神奇但是不懂原理是什么。
26.1 on update cascode;
alter table t_student drop foreign key fk_classes_id;alter table t_student add constraint fk_classes_id_1 foreign key(classes_id) references t_classes(classes_id) on update cascade;select * from t_student;
+------------+--------------+------+------------+-------------+------------+
| student_id | student_name | sex | birthday | email | classes_id |
+------------+--------------+------+------------+-------------+------------+
| 1001 | zhangsan | m | 1998-01-01 | qqq@163.com | 20 |
+------------+--------------+------+------------+-------------+------------+
26.2 on delete cascade
alter table t_student drop foreign key fk_classes_id;alter table t_student add constraint fk_classes_id_1 foreign key(classes_id) references t_classes(classes_id) on delete cascade;delete from t_classes where classes_id = 20;select * from t_classes;
empty setselect * from t_classes;
empty set
27 存储引擎
27.1 完整的建表语句
CREATE TABLE `t_x` (`id` int(11) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;
注意:在MySQL当中,凡是标识符使用飘号括起来的。最好别用,不通用。
建表的时候可以指定存储引擎,也可以指定字符集。
mysql默认使用的存储引擎是InnoDB方式。
默认采用的字符集是UTF-8。
27.2 什么是存储引擎呢?
存储引擎这个名字只有在mysql中存在。
mysql支持很多存储引擎,每个存储引擎都对应了一种不同的存储方式。
每一个存储引擎都有自己的优缺点,需要在合适的时机选择合适的存储引擎。
27.3 当前mysql支持的存储引擎
show engines \G
*************************** 1. row ***************************Engine: ARCHIVESupport: YESComment: Archive storage engine
Transactions: NOXA: NOSavepoints: NO
*************************** 2. row ***************************Engine: BLACKHOLESupport: YESComment: /dev/null storage engine (anything you write to it disappears)
Transactions: NOXA: NOSavepoints: NO
*************************** 3. row ***************************Engine: MRG_MYISAMSupport: YESComment: Collection of identical MyISAM tables
Transactions: NOXA: NOSavepoints: NO
*************************** 4. row ***************************Engine: FEDERATEDSupport: NOComment: Federated MySQL storage engine
Transactions: NULLXA: NULLSavepoints: NULL
*************************** 5. row ***************************Engine: MyISAMSupport: YESComment: MyISAM storage engine
Transactions: NOXA: NOSavepoints: NO
*************************** 6. row ***************************Engine: PERFORMANCE_SCHEMASupport: YESComment: Performance Schema
Transactions: NOXA: NOSavepoints: NO
*************************** 7. row ***************************Engine: InnoDBSupport: DEFAULTComment: Supports transactions, row-level locking, and foreign keys
Transactions: YESXA: YESSavepoints: YES
*************************** 8. row ***************************Engine: MEMORYSupport: YESComment: Hash based, stored in memory, useful for temporary tables
Transactions: NOXA: NOSavepoints: NO
*************************** 9. row ***************************Engine: CSVSupport: YESComment: CSV storage engine
Transactions: NOXA: NOSavepoints: NO
27.4 常见的存储引擎
MyISAM
Engine: MyISAMSupport: YESComment: MyISAM storage engine
Transactions: NOXA: NOSavepoints: 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数据库崩溃之后提供自动恢复机制。
InoDB支持级联删除和级联更新。
MEMORY
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO
缺点:不支持事务。数据容易丢失。因为所有数据和索引都是存储在内存当中的。
优点:查询速度最快。
28 事务
28.1 概述
MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
事务用来管理 insert,update,delete 语句
一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
事务控制语言:
- 事务transaction:一批操作(一组DML)
- 开启事务(start transaction)或(begin)
- 回滚事务(rollback)
- 提交事务(commit)
- set autocommit :禁用或启用事务的自动提交模式,设置事务的隔离级别
- savepoint identifier,savepoint 允许在事务中创建一个保存点,一个事务中可以有多个 savepoint;
- release savepoint identifier 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
- rollback to identifier 把事务回滚到标记点;
当执行DML语句是其实就是开启一个事务
关于事务的回滚需要注意:只能回滚insert、delete和update语句,不能回滚select,create,drop,atler
rollback或者commit后,事务就结束了。
28.2 事务的提交与回滚演示
create table t_sample(
id int(11) primary key not null auto_increment,
username varchar(20),
password varchar(30)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;insert into t_sample (username, password) values('zhangsan','345');
Query OK, 1 row affected (0.01 sec)select * from t_sample;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | zhangsan | 345 |
+----+----------+----------+
1 row in set (0.01 sec)//一个事务的开始
begin;
Query OK, 0 rows affected (0.00 sec)insert into t_sample (username, password) value('lisi','33325');
Query OK, 1 row affected (0.00 sec)//事务提交
commit;
Query OK, 0 rows affected (0.00 sec)select * from t_sample;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | zhangsan | 345 |
| 2 | lisi | 33325 |
+----+----------+----------+
2 rows in set (0.00 sec)//事务开始
begin;
Query OK, 0 rows affected (0.00 sec)insert into t_sample (username, password) value('wangwu','125565');
Query OK, 1 row affected (0.01 sec)//回滚
rollback;
Query OK, 0 rows affected (0.00 sec)//回滚所以数据没有插入
select * from t_sample;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | zhangsan | 345 |
| 2 | lisi | 33325 |
+----+----------+----------+
2 rows in set (0.00 sec)
28.3 自动提交模式
MySQL默认就是自动提交。
直接用 SET 来改变 MySQL 的自动提交模式:
SET AUTOCOMMIT=0 禁止自动提交
SET AUTOCOMMIT=1 开启自动提交
28.4 隔离级别
参考知乎:MySQL事务隔离级别和实现原理(看这一篇文章就够了!)
SET TRANSACTION 用来设置事务的隔离级别。
•事务的隔离级别决定了事务之间可见的级别。
要解决的问题
脏读 dirty read
脏读指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了并一定最终存在的数据,这就是脏读。可重复读 repeatabe read
可重复读指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据都是一致的。通常针对数据更新(UPDATE)操作。不可重复读 non-repeatable read
对比可重复读,不可重复读指的是在同一事务内,不同的时刻读到的同一批数据可能是不一样的,可能会受到其他事务的影响,比如其他事务改了这批数据并提交了。通常针对数据更新(UPDATE)操作。幻读 phantom read
幻读是针对数据插入(INSERT)操作来说的。假设事务A对某些行的内容作了更改,但是还未提交,此时事务B插入了与事务A更改前的记录相同的记录行,并且在事务A提交之前先提交了,而这时,在事务A中查询,会发现好像刚刚的更改对于某些数据未起作用,但其实是事务B刚插入进来的,让用户感觉很魔幻,感觉出现了幻觉,这就叫幻读。
InnoDB 存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。
- 读未提交(READ UMCOMMITTED)
允许一个事务可以看到其他事务未提交的修改。 - 读已提交(READ COMMITTED)
允许一个事务只能看到其他事务已经提交的修改,未提交的修改是不可见的。 - 可重复读(REPEATABLE READ)
确保如果在一个事务中执行两次相同的SELECT语句,都能得到相同的结果,不管其他事务是否提交这些修改。 (银行总账)
该隔离级别为InnoDB的缺省设置。 - 串行化(SERIALIZABLE) 【序列化】
将一个事务与其他事务完全地隔离。
如何设置隔离级别
# 查看事务隔离级别 5.7.20 之后
show variables like 'transaction_isolation';
SELECT @@transaction_isolation# 5.7.20 之后
SELECT @@tx_isolation
show variables like 'tx_isolation'+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
修改隔离级别的语句是:
set [作用域] transaction isolation level [事务隔离级别],
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}。
其中作用于可以是 SESSION 或者 GLOBAL,GLOBAL 是全局的,而 SESSION 只针对当前回话窗口。隔离级别是 {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE} 这四种,不区分大小写。
比如下面这个语句的意思是设置全局隔离级别为读提交级别。
set global transaction isolation level read committe
29 索引
索引用来快速找出在一个列上一特定值的行,没有索引,MySQL会从第一条记录开始搜索,直到读完整个表找到它相关的行
explain select sal from emp where sal > 1500;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 33.33 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.03 sec)
主键、unique都会默认添加索引
29.1 使用索引
什么时候需要给字段添加索引:
- 表中该字段中的数据量庞大
- 经常被检索,经常出现在where子句中的字段
- 经常被DML操作的字段不建议添加索引
如经常根据sal进行查询,并且遇到了性能瓶颈,首先查看程序是否存算法问题,再考虑对sal建立索引,建立索引如下:
create index test_index on emp(sal);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0show index from emp;
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| emp | 0 | PRIMARY | 1 | EMPNO | A | 14 | NULL | NULL | | BTREE | | | YES | NULL |
| emp | 1 | test_index | 1 | SAL | A | 12 | NULL | NULL | YES | BTREE | | | YES | NULL |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+explain select sal from emp where sal > 1500;
//索引是排序的,当我们扫描到第7行时就不会再有符合的数据了,这时候便退出了
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | emp | NULL | range | test_index | test_index | 9 | NULL | 7 | 100.00 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
删除索引
drop index index_name on table_name;
alter table table_name drop index index_name;
alter table table_name drop primary key;
//前两句等价,第3句只在删除primary key索引时使用,因为一个表只可能有一个primary key。
alter table emp drop index test_index;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> explain select sal from emp where sal > 1500;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 33.33 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
30 视图
30.1 什么是视图
视图是一种根据查询(也就是select 表达式)定义的数据库对象,用于获取想要看到和使用的局部数据,是一张虚拟的表,可以在视图上做SQL操作。
图片来源《sql基础教程第2版》
那既然已经有数据表了,为什么还需要视图呢?主要有以下几点原因:
- 通过定义视图可以将频繁使用的SELECT语句保存以提高效率。
- 通过定义视图可以使用户看到的数据更加清晰。
- 通过定义视图可以不对外公开数据表全部字段,增强数据的保密性。
- 通过定义视图可以降低数据的冗余。
30.2 创建视图
基本语法:CREATE VIEW <视图名称>(<列名1>,<列名2>,...) AS <SELECT语句>
create view v_dept_emp as select ename,dname,sal,hiredate,e.deptno from emp e, dept d where e.deptno = d.deptno and e.deptno = 10;
Query OK, 0 rows affected (0.00 sec)select * from v_dept_emp;
+--------+------------+---------+------------+--------+
| ename | dname | sal | hiredate | deptno |
+--------+------------+---------+------------+--------+
| CLARK | ACCOUNTING | 2450.00 | 1981-06-09 | 10 |
| KING | ACCOUNTING | 5000.00 | 1981-11-17 | 10 |
| MILLER | ACCOUNTING | 1300.00 | 1982-01-23 | 10 |
+--------+------------+---------+------------+--------+
3 rows in set (0.01 sec)select dname from v_dept_emp;
+------------+
| dname |
+------------+
| ACCOUNTING |
| ACCOUNTING |
| ACCOUNTING |
+------------+
3 rows in set (0.00 sec)
视图不仅可以基于真实表,我们也可以在视图的基础上继续创建视图。
注意:创建视图的时候不能使用order by子句
why?视图的数据行没有顺序,在 MySQL中视图的定义是允许使用 ORDER BY 语句的,但是若从特定视图进行选择,而该视图使用了自己的 ORDER BY 语句,则视图定义中的 ORDER BY 将被忽略。
30.3 修改视图
alter view v_dept_emp as select ename, dname, sal, hiredate, e.deptno from emp e, dept d where e.deptno = d.deptno and e.deptno = 20;
Query OK, 0 rows affected (0.00 sec)mysql> select * from v_dept_emp;
+-------+----------+---------+------------+--------+
| ename | dname | sal | hiredate | deptno |
+-------+----------+---------+------------+--------+
| SMITH | RESEARCH | 800.00 | 1980-12-17 | 20 |
| JONES | RESEARCH | 2975.00 | 1981-04-02 | 20 |
| SCOTT | RESEARCH | 3000.00 | 1987-04-19 | 20 |
| ADAMS | RESEARCH | 1100.00 | 1987-05-23 | 20 |
| FORD | RESEARCH | 3000.00 | 1981-12-03 | 20 |
+-------+----------+---------+------------+--------+
30.4 更新视图
对于一个视图来说,如果包含以下结构的任意一种都是不可以被更新的:
- 聚合函数 SUM()、MIN()、MAX()、COUNT() 等。
- DISTINCT 关键字。
- GROUP BY 子句。
- HAVING 子句。
- UNION 或 UNION ALL 运算符。
- FROM 子句中包含多个表。
update v_dept_emp set sal = '3001' where ename = 'FORD';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0select * from v_dept_emp where ename = 'FORD';
+-------+----------+---------+------------+--------+
| ename | dname | sal | hiredate | deptno |
+-------+----------+---------+------------+--------+
| FORD | RESEARCH | 3001.00 | 1981-12-03 | 20 |
+-------+----------+---------+------------+--------+
1 row in set (0.00 sec)//原表的数据也被修改了
select * from emp where ename = 'FORD';
+-------+-------+---------+------+------------+---------+------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+-------+---------+------+------------+---------+------+--------+
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3001.00 | NULL | 20 |
+-------+-------+---------+------+------------+---------+------+--------+
1 row in set (0.00 sec)
因为会修改原标的数据,而且只能对视图中的部分作出修改,尽量不要使用这种修改方式。
30.5 删除视图
drop view if exists v_dept_emp;
MySQL基础入门【3】相关推荐
- 自己总结的MySQL基础入门知识,附思维导图
第一次写博文,问题点可能比较多,辛苦大家帮忙指正,感谢大家. MySQL基础入门知识 前言 一.数据库基础知识 1.什么是数据库 2.数据库的分类 3.数据库的常用语言 4.数据库的常用操作方式 5. ...
- MySQL基础入门篇
MySQL基础和SQL入门 1.数据库 1.1使用数据库的原因 存储方式 优点 缺点 内存 速度快 不能够永久保存,数据是临时状态的 文件 数据是可以永久保存的 使用IO流操作文件, 不方便 数据库 ...
- mysql基础入门 day2 动力节点[老杜]课堂笔记
day_2 本文原作者为动力节点教学总监杜老师老杜在其课老杜带你学_mysql 入门基础(mysql 基础视频+数据库实战)所写讲课笔记 该文档和其涉及资料见文档末链接 本人将其讲课笔记 txt 下载 ...
- MySQL基础入门到精通学习教程汇总【基础+高级完整版】
MySQL是最流行的关系型数据库管理系统之一,这也是我们为什么要学习MySQL数据的库的原因之一,就连非互联网行业的人士也在开始学习MySQL去分析数据. 对于程序员来说,MySQL数据库更是需要熟练 ...
- mysql 同一张表 某个字段更新到另一条数据上_面试基础:数据库MySQL基础入门(下)...
本文是面试基础的第二篇.本篇偏理论,包括三节: 事务和并发 数据库设计 索引 所选的三个内容均是面试的高频考察点,需要细致地理解 No.1 事务和并发 事务:数据库操作的基本单元.对于数据库的 ...
- mysql基础入门SQL基本语法
SQL:Structure Query Language(结构化查询语言)简称SQL,数据库管理系统可以通过SQL管理数据库:定义和操作数据,维护数据的完整性和安全性. SQL的分类: 1.DDL(D ...
- Mysql基础入门篇(二)
一.约束 1.什么是约束? 概念: 对表中的数据进行限定,保证数据的正确性.有效性和完整性. 2.约束的分类 主键约束:primary key 非空约束:not null 唯一约束:unique 外键 ...
- mysql 基础入门及单表查询
mysql单表 今日内容介绍 数据库: 数据库管理系统 使用数据库管理系统通过sql语句 创建数据库,创建表,插入数据,更新数据,删除数据,查询数据 数据库约束 数据库的备份还原 数据库的内容比较多, ...
- MySQL基础入门到索引优化
MySql 1. 什么是数据库 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库.mysql是关系型数据库管理系统(RDBMS)来存储和管理大数据量.所谓的关系型数据库,是建立在关 ...
最新文章
- 腾讯云宣布核心产品全线降价,最高降幅达50%
- 璧山哪里可以学基础计算机,璧山学电脑在哪里
- java list布局_java – 使用2种不同的布局重用Android Listvi...
- Windows下安装Apache 2.2.21图文教程
- Django中实现MySQL主从同步实现读写分离
- python串口模块_Python使用pip安装pySerial串口通讯模块
- Asp.Net中Cache操作类
- cmd 出现The system cannot write to the specified device问题时如何解决
- 图片没有.png或者jpg后缀能不能加载?
- ID与Class的区别(#与。的区别)CSS
- SAPAS91导入期初固定资产数据往年购置与当年购置的区别
- 存活探针(Liveness Probe)
- xposed绕过模拟器检测_刺激战场过模拟器检测 刺激战场模拟器检测怎么绕过
- utc时间怎么转换北京时间?
- Word 在试图打开文件时遇到错误 解决办法
- Avalonia UI 简介
- Asp.net Core使用Microsoft.Office.Interop.Word转换文档
- ksy是谁_sky为什么叫人皇:sky是谁及资料
- dz论坛php5,S!淘专辑 3.0.1 For php5.2 php5.3版 dz插件分享,淘专辑是用户将喜欢的论坛帖子...
- greenplum数据库单机部署