学习于动力节点的杜老师:https://www.bilibili.com/video/BV1Vy4y1z7EX?p=1
三者之间的关系?
DBMS --执行–> SQL语句 --操作–> DB
先安装数据库管理系统MySQL,然后学习SQL语句怎么写,编写SQL语句之后,DBMS对SQL语句进行执行,最终来完成数据库的数据管理。
…
…
MySQL的卸载
第一步:双击安装包进行卸载删除
第二部:删除目录:
把c:\ProgramData 下面的MySQL目录干掉
把c:\ProgramFile(x86) 下面的MySQL目录干掉
window操作系统终端启动和关闭(注意以分号结尾)
语法:
net stop 服务名称;
net start 服务名称;
终端登录:
mysql -uroot -p123456;
mysql -uroot -p; 123456;
退出终端:exit;
exit
:退出mysqlshow databases;
:查看数据库有哪些数据库,注意以英文分号结尾(MySQL默认自带4个数据库)use test
:使用某个数据库,表示正在使用名字叫做test的数据库create database 名字
:创建一个数据库show tables
:查看数据库中的表desc 表名
:查看表结构select version()
:查看数据版本号select database()
:查看使用的是哪个数据库什么是table?为什么用表来存储数据呢?
数据库当中是以表格的形式表示数据的。
因为表比较直观。
任何一张表都有行和列:
行(row):被称为数据/记录。
列(column):被称为字段。
每一个字段都有:字段名、数据类型、约束等属性。
字段名可以理解,是一个普通的名字,见名知意就行。
1、select * from dept;
这种方式的缺点:
在实际开发中不建议,可以自己玩没问题。
你可以在DOS命令窗口中想快速的看一看全表数据可以采用这种方式。
2、别名
select deptno as no from dept;
使用as关键字接在要查询字段的后面,可以省略
若是别名有空格,则可以使用单引号括起来
在数据库中,字符串统一使用单引号括起来。其中中文一定要括起来
mysql> select deptno,dname 'dept name' from dept;
+--------+------------+
| deptno | dept name |
+--------+------------+
| 10 | ACCOUNTING |
| 20 | RESEARCH |
| 30 | SALES |
| 40 | OPERATIONS |
+--------+------------+
4 rows in set (0.00 sec)
3、字段可以使用数学表达式
mysql> select ename,sal from emp;
+--------+---------+
| ename | sal |
+--------+---------+
| SMITH | 800.00 |
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| JONES | 2975.00 |
| MARTIN | 1250.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| FORD | 3000.00 |
| MILLER | 1300.00 |
+--------+---------+
14 rows in set (0.00 sec)
mysql> select ename,sal*12 from emp;
+--------+----------+
| ename | sal*12 |
+--------+----------+
| SMITH | 9600.00 |
| ALLEN | 19200.00 |
| WARD | 15000.00 |
| JONES | 35700.00 |
| MARTIN | 15000.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| SCOTT | 36000.00 |
| KING | 60000.00 |
| TURNER | 18000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| FORD | 36000.00 |
| MILLER | 15600.00 |
+--------+----------+
14 rows in set (0.00 sec)
语法格式
select
字段1,字段2
from
表名
where 条件;
条件项
=
:等于<>或!=
:不等于<
:小于<=
:小于等于>
:大于>=
:大于等于between ... and ...
:两个值之间,等同于>= and <=
,必须遵从左小右大,并且这个是闭区间。is null
:为null(is not null
不为空)and
:并且,and
比or
优先级更高or
:或者in
:包含,相当于多个or
(not in
不在这个范围中),in
后加的是具体的值,不是区间。not
:not
可以取非,主要用在is
或 in
中,不可以和=
号使用。like
:like
称为模糊查询,支持%或下划线匹配,%
:匹配任意个字符,下划线
:一个下划线只匹配一个字符,需要查询到_
时候,可以使用\
转义。order by 字段名
:排序,默认是升序,若要降序,字段名后面加desc
,asc
就是升序;若是多个字段名排序就加入多个字段名,如order by 字段名1,字段名2
;也可以用字段的位置进行排序,如order by 2
,2表示第二列。实验
mysql> select empno,ename from emp where sal = 800;
+-------+-------+
| empno | ename |
+-------+-------+
| 7369 | SMITH |
+-------+-------+
1 row in set (0.05 sec)
mysql> select empno,ename from emp where sal != 800;
+-------+--------+
| empno | ename |
+-------+--------+
| 7499 | ALLEN |
| 7521 | WARD |
| 7566 | JONES |
| 7654 | MARTIN |
| 7698 | BLAKE |
| 7782 | CLARK |
| 7788 | SCOTT |
| 7839 | KING |
| 7844 | TURNER |
| 7876 | ADAMS |
| 7900 | JAMES |
| 7902 | FORD |
| 7934 | MILLER |
+-------+--------+
13 rows in set (0.00 sec)
mysql> select empno,ename from emp where sal<2000;
+-------+--------+
| empno | ename |
+-------+--------+
| 7369 | SMITH |
| 7499 | ALLEN |
| 7521 | WARD |
| 7654 | MARTIN |
| 7844 | TURNER |
| 7876 | ADAMS |
| 7900 | JAMES |
| 7934 | MILLER |
+-------+--------+
8 rows in set (0.00 sec)
mysql> select empno,ename from emp where sal<=3000;
+-------+--------+
| empno | ename |
+-------+--------+
| 7369 | SMITH |
| 7499 | ALLEN |
| 7521 | WARD |
| 7566 | JONES |
| 7654 | MARTIN |
| 7698 | BLAKE |
| 7782 | CLARK |
| 7788 | SCOTT |
| 7844 | TURNER |
| 7876 | ADAMS |
| 7900 | JAMES |
| 7902 | FORD |
| 7934 | MILLER |
+-------+--------+
13 rows in set (0.00 sec)
又称为单行处理函数,特点就是一个输入对应一个输出,与单行处理函数相对的就是多行处理函数(多行处理函数特点就是多个输入,对应一个输出)
自悟:单行处理函数就是函数处理多条条数据后,返回的数据还是那几个多条。多行处理函数就是处理多条记录的函数,返回只有一条数据。
如果sql查询的字面量,则它会使用查询的表结构返回一列字面量
lower
:转换小写upper
:转换大写substr
:取子串,截取字符串,参数1是下标,参数2是截取长度,下标从1开始length
:取长度trim
:去空格str_to_date
:将字符串转换成日期date_format
:格式化日期format
:设置千分位round
:四舍五入,第二个参数可以设置保留位数,0的时候是整数,可以到负数rand()
:生成随机数,只会生成0到1的随机数concat(字符串1,字符串2)
:将字符串1,2拼接ifnull
:可以将 null 转换成一个具体的值,因为null参与计算会导致结果都为null,参数1对应哪一列,第二个如果为null那么的默认值case 字段名 when 字段匹配的值1 then 显示的值1 when 字段匹配的值1 then 显示的值2 else 最后的显示的值 end
:不会修改数据库,例子select ename,job,(case job when ‘MANAGER’ then sal1.1 when ‘SALESMAN’ then sal1.5 else sal end) as newsal from emp;分组函数操作的是分组后的表里面的最小层级的每一个组
使用分组函数,那么查的一定是参加分组的字段以及分组函数,切记切记
又称为多行处理函数,特点输入多行,最终输出一行。
5个
count
:计数,若是具体的某一列则查的就是不为null的个数,*查的就是全部行数sum
:求和avg
:平均数max
:最大值min
:最小值注意:
分组函数在使用的时候必须先进行分组,然后才能使用。
如果没有分组,则默认一张表就是一组
分组函数自动忽略null,不需要处理null
分组函数不能直接使用在where子句中
所有的分组函数可以组合在一起用
什么是分组查询?
在实际的应用中,可能有这样的需求,需要先进行分组,然后对每一组的数据进行操作。
这个时候我们需要使用分组查询,怎么进行分组查询呢?
select …
from …
group by …(最后面的…就是要分组的字段)
将之前的关键字组合在一起,查看执行顺序
select ...
from ...
where ...
group by ...
order by ...
以上关键字的顺序不能颠倒,需要记忆
执行顺序:
为什么分组函数不能直接使用在where 后面?
因为分组函数在使用的时候必须先分组之后才能使用。
where执行的时候,还没有分组。所以where后面不能出现分组函数。
select sum(sal) from emp;
这个没有分组,为啥sum() 函数可以用呢?
因为select在group by 之后执行
自悟:分组函数不能在where后面直接使用
实验
找出“每个部门,不同工作岗位”的最高工资?
只能进行双重分组(先分组depton再分组job)
mysql> select deptno,job,max(sal) from emp group by deptno,job;
+--------+-----------+----------+
| deptno | job | max(sal) |
+--------+-----------+----------+
| 10 | CLERK | 1300.00 |
| 10 | MANAGER | 2450.00 |
| 10 | PRESIDENT | 5000.00 |
| 20 | ANALYST | 3000.00 |
| 20 | CLERK | 1100.00 |
| 20 | MANAGER | 2975.00 |
| 30 | CLERK | 950.00 |
| 30 | MANAGER | 2850.00 |
| 30 | SALESMAN | 1600.00 |
+--------+-----------+----------+
9 rows in set (0.00 sec)
having的使用,对分组过后的数据进行过滤
执行在where后面,有点影响效率,推荐可以使用where过滤就使用它过滤,实在不行再用having。
这一定要接在group by 后面使用
过滤的时候要求函数后的比较只能在having里面使用
比如:找出每个部门平均工资,要求显示的平均工资高于2500的
mysql> select deptno,avg(sal)
-> from emp
-> group by deptno
-> having avg(sal) > 2500;
+--------+-------------+
| deptno | avg(sal) |
+--------+-------------+
| 10 | 2916.666667 |
+--------+-------------+
1 row in set (0.04 sec)
select ...
from ...
where ...
group by ...
having ...
order by ...
执行顺序?
也就是:从这张表中过滤,过滤后分组,不满意再过滤,然后查询,最后排序
删除重复记录
把查询结果去除重复激励
注意:原表数据不会被改变,只是查询结果去重
关键字:distinct
使用在要查询字段的最前面,去除后面字段所有重复记录
mysql> select distinct job from emp;
+-----------+
| job |
+-----------+
| CLERK |
| SALESMAN |
| MANAGER |
| ANALYST |
| PRESIDENT |
+-----------+
5 rows in set (0.04 sec)
mysql>
根据表连接的方式分类:
当两张表连接查询时,没有任何条件的限制会发生什么现象?
当两张表连接查询时,没有任何条件的限制的时候,最终查询结果条数,时两张表条数的乘积,这种现象被称为:笛卡尔积现象。
怎么避免笛卡尔积现象?
连接时加条件,满足整个条件的记录被筛选出来
mysql> select ename,dname from emp,dept where emp.deptno = dept.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.08 sec)
mysql> select e.ename,d.dname from emp e,dept d where e.deptno = d.deptno;
指定字段属于哪张表中,可以提高效率,所以要使用别名。
注意:最终查询的结果条数是14条,但是匹配的过程中,匹配的次数没有减少。即连接次数越多效率越低,尽量避免表的连接次数。
内连接
特点:完成能够匹配这个条件的数据查询出来。(取交集)
等值连接(条件是等量关系)
sql92连接写法:
select e.ename,d.dname
from emp e,dept d
where e.deptno = d.deptno;
sql92的缺点:结构不清晰,表的连接条件,和后期进一步筛选的条件,都放在where条件后面
sql99的写法:
select e.ename,d.dname
from emp e
join dept d
on e.deptno = d.deptno;
sql99优点:表连接的条件是独立的,连接之后,如果还需要进一步筛选,再往后继续添加where
非等值连接(条件不是一个等量关系,称为非等值连接)
案例:找出每个员工的薪资等级,要求显示员工工名、薪资、薪资等级?
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.04 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)
select e.ename,e.sal,s.grade
from emp e
join salgrade s
on e.sal between s.losal and s.hisal;
自连接
案例:查询员工的上级领导,要求显示员工名和对应的领导名?
mysql> select a.ename as '员工名',b.ename as '领导名'
-> from emp a join emp b on a.mgr = b.empno;
+--------+--------+
| 员工名 | 领导名 |
+--------+--------+
| 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 |
+--------+--------+
13 rows in set (0.08 sec)
将一张表当两张表用
右外连接
right代表什么:表示将join关键字右边的这张表堪称主表,主要是为了将这张表的数据全部查询出来,捎带着关联查询左边的表。在外连接当中,两张表连接,产生了主次关系。
mysql> select e.ename,d.dname
-> from emp e right 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 |
| NULL | OPERATIONS |
+--------+------------+
15 rows in set (0.00 sec)
左外连接
mysql> select e.ename,d.dname
-> from dept d left join emp e
-> 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 |
| NULL | OPERATIONS |
+--------+------------+
15 rows in set (0.00 sec)
带有right的是右外连接,又叫右连接。
带有left的是左外连接,又叫左连接。
任何一个右连接都有左连接的写法。
任何一个左连接都有右连接的写法。
思考:外连接的查询结果条数一定是 >= 内连接的查询结果条数? 正确
语法:
select ...
from a
join b
on a和b的连接条件
join c
on a和c的连接条件
join d
on a和d的连接条件
一条sql中内连接和外连接可以混合。
案例:找出每个员工的部门名称以及部门等级,要求显示员工名、部门名、薪资名、薪资等级?
mysql> select e.ename,e.sal,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;
+--------+---------+------------+-------+
| ename | sal | dname | grade |
+--------+---------+------------+-------+
| SMITH | 800.00 | RESEARCH | 1 |
| ALLEN | 1600.00 | SALES | 3 |
| WARD | 1250.00 | SALES | 2 |
| JONES | 2975.00 | RESEARCH | 4 |
| MARTIN | 1250.00 | SALES | 2 |
| BLAKE | 2850.00 | SALES | 4 |
| CLARK | 2450.00 | ACCOUNTING | 4 |
| SCOTT | 3000.00 | RESEARCH | 4 |
| KING | 5000.00 | ACCOUNTING | 5 |
| TURNER | 1500.00 | SALES | 3 |
| ADAMS | 1100.00 | RESEARCH | 1 |
| JAMES | 950.00 | SALES | 1 |
| FORD | 3000.00 | RESEARCH | 4 |
| MILLER | 1300.00 | ACCOUNTING | 2 |
+--------+---------+------------+-------+
14 rows in set (0.00 sec)
要点:找出主表,找出要从每个表获取的字段即可。
什么是子查询?
select语句中嵌套select语句,被嵌套的select语句称为子查询。
子查询都可以出现在哪里呢?
select ..(select). //这里的select只能给一条字段
from ..(select).
where ..(select).
案例:找出比最低工资高的员工姓名和工资?
mysql> select ename,sal
-> from emp
-> where sal > min(sal);
ERROR 1111 (HY000): Invalid use of group function
where中不能直接使用分组函数
实现思路:
第一步:查询最低工资是多少?
mysql> select min(sal)
-> from emp;
+----------+
| min(sal) |
+----------+
| 800.00 |
+----------+
1 row in set (0.02 sec)
第二步:找出大于800的
select ename,sal
from emp
where sal > 800;
第三步:合并
mysql> select ename,sal
-> from emp
-> where sal > (select min(sal) from emp);
+--------+---------+
| ename | sal |
+--------+---------+
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| JONES | 2975.00 |
| MARTIN | 1250.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| FORD | 3000.00 |
| MILLER | 1300.00 |
+--------+---------+
13 rows in set (0.01 sec)select ename,sal
from emp
where sal > (select min(sal) from emp);
注意:from后面的子查询,可以将子查询结果当作一张临时表看待。(技巧)
案例:找出每个岗位的平均工资的薪资等级
第一步:找出每个岗位的平均工资(按照岗位分组求平均值)
mysql> select job,avg(sal) from emp group by job;
+-----------+-------------+
| job | avg(sal) |
+-----------+-------------+
| ANALYST | 3000.000000 |
| CLERK | 1037.500000 |
| MANAGER | 2758.333333 |
| PRESIDENT | 5000.000000 |
| SALESMAN | 1400.000000 |
+-----------+-------------+
5 rows in set (0.05 sec)
第二步:将第一步的临时表 t,用t表连接薪资等级表
select job,t.a,grade
from (select job,avg(sal) a from emp group by job) t
join salgrade
on t.a between losal and hisal;
对于select后面的子查询来说,这个子查询只能一次返回1条结果,超过则错误。
案例:查询工作岗位是MANAGER和SALESMAN的员工?
mysql> select ename,job
-> from emp
-> where job ='MANAGER' or job ='SALESMAN';
+--------+----------+
| ename | job |
+--------+----------+
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| JONES | MANAGER |
| MARTIN | SALESMAN |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| TURNER | SALESMAN |
+--------+----------+
7 rows in set (0.00 sec)
mysql> select ename,job
-> from emp
-> where job in('MANAGER','SALESMAN');
+--------+----------+
| ename | job |
+--------+----------+
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| JONES | MANAGER |
| MARTIN | SALESMAN |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| TURNER | SALESMAN |
+--------+----------+
7 rows in set (0.00 sec)
mysql> 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)
union的效率要高一些,对于表连接来说,每连接一次新表,
则匹配的次数满足笛卡尔积,成倍的翻…
但是union可以减少匹配的次数。在减少匹配次数的情况下,
还可以完成两个结果集的拼接。
也就是说当三表连接的时候:
a 连接 b 连接 c
a 10条记录
b 10条记录
c 10条记录
则匹配次数是:10*10*10=1000
由上我们使用连接union时候
匹配次数就是:10*10+10*10=200
所以当要使用到3张表的时候,最好使用union
注意事项:union在进行的结果集合并的时候,要求结果集的列数相同以及结果集的列和列的数据类型也要相同。
limit是将查询结果集的一部分取出来,通常使用在分页查询当中。
完整用法:limit startIndex,length
案例:按照薪资降序,取出排名在前5名的员工?
mysql> select ename,sal
-> from emp
-> order by sal desc
-> limit 5;
+-------+---------+
| ename | sal |
+-------+---------+
| KING | 5000.00 |
| FORD | 3000.00 |
| SCOTT | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
5 rows in set (0.00 sec)
注意:mysql当中limit在order by之后执行!!!!!!
每页显示3(pagesize)条记录
公式:
起始下标:(页数-1)*pagesize
limit (pageNo-1)*pagesize,pagesize
select ...
from ...
where ..
group by ...
having ...
order by ...
limit ...
执行顺序:
create table 表名(
字段名1 据类型1,
字段名2 据类型2,
字段名3 据类型3
);
表名:建议以 t_ 或者 tbl_ 开始,可读性强。见名知义。
字段名:见名知义。
表名和字段名都属于标识符。
create table t_student(
no int,
name varchar(32),
sex char(1),
age int(3),
email varchar(32)
);
drop table 表名; //当这张表不存在的时候会报错!
drop table if exists 表名; //如果这张表存在的话,删除。
语法格式:
insert into 表名(字段名1,字段名2,字段名3....)
values
(值1,值2,值3...),
(值1,值2,值3...);
注意:字段名和值要一一对应,什么是一一对应?数量要对应,数据类型要对应。
insert into t_student(no,name,sex,age,email)
values
(1,'zhangsan','男',22,'[email protected]');
注意插入一条记录没有设置一些字段的非空,则其他字段会编成null:
mysql> insert into t_student(no)
-> values
-> (6);
Query OK, 1 row affected (0.04 sec)
mysql> select * from t_student;
+------+----------+------+------+------------------+
| no | name | sex | age | email |
+------+----------+------+------+------------------+
| 1 | zhangsan | 男 | 22 | 295349478@qq.com |
| 6 | NULL | NULL | NULL | NULL |
+------+----------+------+------+------------------+
2 rows in set (0.00 sec)
注意:insert 语句但凡是执行成功了,那么必然会多一条记录。没有给其他字段指定值,默认值是null。
在建表的时候,字段后面使用default
create table t_student(
no int,
name varchar(32),
sex char(1) default '男',
age int(3),
email varchar(32)
);
表结构
mysql> desc t_student;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| no | int(11) | YES | | NULL | |
| name | varchar(32) | YES | | NULL | |
| sex | char(1) | YES | | 男 | |
| age | int(3) | YES | | NULL | |
| email | varchar(32) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)
insert语句中的“字段名“可以省略吗?可以
注意:省略字段名的话相当于全部写上了,如此所有的字段的值也要写上。
推荐使用上面的方式,可读性强。
函数数字格式化:format(数字,‘格式’)
mysql> select ename,format(sal,'$999,999') as sal from emp;
+--------+-------+
| ename | sal |
+--------+-------+
| SMITH | 800 |
| ALLEN | 1,600 |
| WARD | 1,250 |
| JONES | 2,975 |
| MARTIN | 1,250 |
| BLAKE | 2,850 |
| CLARK | 2,450 |
| SCOTT | 3,000 |
| KING | 5,000 |
| TURNER | 1,500 |
| ADAMS | 1,100 |
| JAMES | 950 |
| FORD | 3,000 |
| MILLER | 1,300 |
+--------+-------+
14 rows in set, 14 warnings (0.00 sec)
其中$999,999代表千分位。
str_to_date:将字符串varchar类型转换成date类型。
date_format:将date类型转换成varchar类型。
create table t_user(
id int,
name varchar(32),
birth date
);
create table t_user(
id int,
name varchar(32),
birth char(10) //十日可以使用char类型
);
生日:1990-10-11 (刚好10个字符)
注意:数据库中有一条命名规范:所有的标识符(也就是表名和字段名)都是全部小写,单词和单词之间使用下划线进行衔接。
mysql> desc t_user;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(32) | YES | | NULL | |
| birth | date | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
插入数据?
错误插入方式
insert into t_user(in,name,birth) values(1,'zhangsan','11-10-1990')
数据库类型不匹配,日期需要的是日期类型,'11-10-1990'是字符串
需要使用str_to_date将字符串转换成字符串
str_to_date的语法格式:
str_to_date('字符串日期','日期格式')
其中日期和日期格式要对应
mysql的日期格式:
%Y 年
%m 月
%d 日
%h 时
%i 分
%s 秒
正确插入方式:
insert into t_user(id,name,birth) values(1, 'zhangsan', str_to_date('01-10-1990','%d-%m-%Y'));
str_to_date 函数可以把字符串varchar转换成日期date类型数据,通常使用在插入insert方面,因为插入的时候需要一个日期类型的数据,需要通过该函数将字符串转换成date。
注意:如果提供的日期字符串是这个格式(%Y-%m-%d),str_to_date 函数就不需要了!!!
mysql> insert into t_user(id,name,birth) values (2,'lisi','2021-05-23');
Query OK, 1 row affected (0.06 sec)
mysql> select * from t_user;
+------+----------+------------+
| id | name | birth |
+------+----------+------------+
| 1 | zhangsan | 1990-10-01 |
| 2 | lisi | 2021-05-23 |
+------+----------+------------+
2 rows in set (0.00 sec)
查询的时候可以以一个特定的日期格式展示吗?
select id,name,date_format(birth,'%m/%d/%y') from t_user;
mysql> select id,name,date_format(birth,'%Y/%m/%d') from t_user;
+------+----------+-------------------------------+
| id | name | date_format(birth,'%Y/%m/%d') |
+------+----------+-------------------------------+
| 1 | zhangsan | 1990/10/01 |
| 2 | lisi | 2021/05/23 |
+------+----------+-------------------------------+
2 rows in set (0.00 sec)
date_format函数怎么用?
date_format(日期类型数据,‘日期格式’)
这个函数通常使用在查询在查询日期方面。设置展示的日期格式。
直接查询返回的日期格式会是怎么样的?
mysql> select id,name,birth from t_user;
+------+----------+------------+
| id | name | birth |
+------+----------+------------+
| 1 | zhangsan | 1990-10-01 |
| 2 | lisi | 2021-05-23 |
+------+----------+------------+
2 rows in set (0.00 sec)
会展示mysql的默认日期格式,将数据库中的日期自动转化为varchar类型'%Y-%m-%d'
date是短日期:只包括年月日信息。
datetime是长日期:包括年月日时分秒信息。
drop table if exists t_user;
create table t_user(
id int,
name varchar(32),
birth date,
create_time datetime
);
insert into t_user(id,name,birth,create_time)
values
(1,'zhangsan','1990-10-01','1990-10-01 16:40:22');
mysql> select * from t_user;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 1990-10-01 | 1990-10-01 16:40:22 |
+------+----------+------------+---------------------+
1 row in set (0.00 sec)
在mysql当中怎么获取系统当前时间?
now() 函数,并且获取的时间带有:时分秒信息!!
insert into t_user(id,name,birth,create_time)
values
(2,'lisi','2000-10-01',now());
mysql> insert into t_user(id,name,birth,create_time)
-> values
-> (2,'lisi','2000-10-01',now());
Query OK, 1 row affected (0.06 sec)
mysql> select * from t_user;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 1990-10-01 | 1990-10-01 16:40:22 |
| 2 | lisi | 2000-10-01 | 2021-09-25 18:13:57 |
+------+----------+------------+---------------------+
2 rows in set (0.00 sec)
虽然now()函数获取的时间带有时分秒信息,但是也可以插入到date短日期数据类型中。
insert into t_user(id,name,birth,create_time)
values
(3,'wangwu',now(),now());
mysql> insert into t_user(id,name,birth,create_time)
-> values
-> (3,'wangwu',now(),now());
Query OK, 1 row affected, 1 warning (0.03 sec)
mysql> select * from t_user;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 1990-10-01 | 1990-10-01 16:40:22 |
| 2 | lisi | 2000-10-01 | 2021-09-25 18:13:57 |
| 3 | wangwu | 2021-09-25 | 2021-09-25 18:15:43 |
+------+----------+------------+---------------------+
3 rows in set (0.00 sec)
语法格式:
update 表名 set 字段名1=值1,字段名2=值2,字段名3=值3.... where 条件;
注意:没有条件限制会导致所有数据全部更新。
update t_user set name = 'jack',birth = '2021-03-22' where id = 2;
mysql> select * from t_user;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 1990-10-01 | 1990-10-01 16:40:22 |
| 2 | jack | 2021-03-22 | 2021-09-25 18:13:57 |
| 3 | wangwu | 2021-09-25 | 2021-09-25 18:15:43 |
+------+----------+------------+---------------------+
3 rows in set (0.00 sec)
更新所有?
update t_user set birth = '1990-10-01';
mysql> select * from t_user;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 1990-10-01 | 1990-10-01 16:40:22 |
| 2 | jack | 1990-10-01 | 2021-09-25 18:13:57 |
| 3 | wangwu | 1990-10-01 | 2021-09-25 18:15:43 |
+------+----------+------------+---------------------+
3 rows in set (0.00 sec
语法格式:
delete from 表名 where 条件;
注意:没有条件,整张表的数据全部删除!
delete from t_user where id = 3;
delete from t_user; //删除所有
mysql> delete from t_user where id = 3;
Query OK, 1 row affected (0.06 sec)
mysql> select * from t_user;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 1990-10-01 | 1990-10-01 16:40:22 |
| 2 | jack | 1990-10-01 | 2021-09-25 18:13:57 |
+------+----------+------------+---------------------+
2 rows in set (0.00 sec)
mysql> delete from t_user;
Query OK, 2 rows affected (0.07 sec)
mysql> select * from t_user;
Empty set (0.00 sec)
连接是本质其实是匹配,进行笛卡尔积,然后选择满足条件的。可以看占比图,只有占比图出来才可以选择其中的部分。
内外连接的理解:两张表平等关系就是内连接join,若有主次关系left join,则是外连接。
insert into t_user(id,name,birth,create_time)
values
(1,'zhangsan',now(),now()),
(2,'lisi',now(),now()),
(3,'wangwu',now(),now());
mysql> insert into t_user(id,name,birth,create_time)
-> values
-> (1,'zhangsan',now(),now()),
-> (2,'lisi',now(),now()),
-> (3,'wangwu',now(),now());
Query OK, 3 rows affected, 3 warnings (0.05 sec)
Records: 3 Duplicates: 0 Warnings: 3
mysql> select * from t_user;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 2021-09-26 | 2021-09-26 00:06:23 |
| 2 | lisi | 2021-09-26 | 2021-09-26 00:06:23 |
| 3 | wangwu | 2021-09-26 | 2021-09-26 00:06:23 |
+------+----------+------------+---------------------+
3 rows in set (0.00 sec)
create table t_user2 as select * from t_user;
mysql> create table t_user2 as select * from t_user;
Query OK, 3 rows affected (0.30 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from t_user2;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 2021-09-26 | 2021-09-26 00:06:23 |
| 2 | lisi | 2021-09-26 | 2021-09-26 00:06:23 |
| 3 | wangwu | 2021-09-26 | 2021-09-26 00:06:23 |
+------+----------+------------+---------------------+
3 rows in set (0.00 sec)
原理:
将查询结果当作一张表新建!!!
同时将表中的数据也存在了。
加条件可以选择列和存入的数据!
create table t_user3 as select id,name from t_user where id =1;
mysql> create table t_user3 as select id,name from t_user where id =1;
Query OK, 1 row affected (0.37 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from t_user3;
+------+----------+
| id | name |
+------+----------+
| 1 | zhangsan |
+------+----------+
1 row in set (0.00 sec)
insert into t_user2 select * from t_user; //将查询到东西插入的表中(很少用)
//删除t_user3表中的数据(属于DML语句)
delete from t_user3;
//这样删除数据的方式比较慢
//删除数据的原理?
表中的数据被删除了,但是这个数据在硬盘上的真实存储空间不会被释放!!!
缺点:删除效率比较低;
优点:支持回滚,后悔了可以再恢复数据!!
mysql> select * from t_user;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 2021-09-26 | 2021-09-26 00:06:23 |
| 2 | lisi | 2021-09-26 | 2021-09-26 00:06:23 |
| 3 | wangwu | 2021-09-26 | 2021-09-26 00:06:23 |
+------+----------+------------+---------------------+
3 rows in set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from t_user;
Query OK, 3 rows affected (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.06 sec)
mysql> select * from t_user;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 2021-09-26 | 2021-09-26 00:06:23 |
| 2 | lisi | 2021-09-26 | 2021-09-26 00:06:23 |
| 3 | wangwu | 2021-09-26 | 2021-09-26 00:06:23 |
+------+----------+------------+---------------------+
3 rows in set (0.00 sec)
truncate 语句删除数据的原理?
这种删除效率比较高,表被一次阶段,物理删除。
缺点:不支持回顾
优点:快,效率高
mysql> use du;
Database changed
mysql> truncate table t_user3;
Query OK, 0 rows affected (0.29 sec)
用法:truncate table t_user3;
这种操作属于DDL操作;
如果大表非常大,上亿条记录??
删除的时候,使用delete,也许需要执行1个小时才能删除完!效率较低。
可以选择使用truncate删除表中的数据。只需要不到1秒钟的时间就删除结束。效率较高。
但是使用truncate之前,必须反复询问客户是否真的需要,并警告删除不可恢复。
truncate删除是删除表中全部的数据,但是表结构还在!
删除表操作?
drop table 表名; //这不是删除表中的数据,这是把表删了
添加一个字段,删除一个字段,修改一个字段!!
对表结构的修改需要使用:alter
属于DDL语句
DDL包括:create drop alter
修改表结构的操作是不需要写道java程序中的,实际上也不是java程序员的范畴。
约束的作用就是为了保证:表中的数据有效!!
非空约束:not null 约束的字段不能为NULL。
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(32) not null
);
insert into t_vip(id,name)
values
(1,'zhangsan'),
(2,'lisi');
xxxx.sql这种文件被称为sql脚本文件。
sql脚本文件中编写了大量的sql 语句。
我们执行sql脚本文件的时候,该文件中所有的sql语句会全部执行。
批量的执行sql语句,可以使用sql脚本文件。
使用:
mysql> source D:/Program Files/MySql_study/t_vip.sql;
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 0 rows affected (0.29 sec)
Query OK, 1 row affected (0.02 sec)
Query OK, 1 row affected (0.03 sec)
mysql> insert into t_vip(id)
-> values
-> (3);
ERROR 1364 (HY000): Field 'name' doesn't have a default value
//没有默认值,一定要插入数据
唯一性约束:unique 约束的字段不能重复,但是可以为null,也就是重复为null;
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(32) unique,
email varchar(255)
);
insert into t_vip(id,name,email)
values
(1,'zhangsan','[email protected]');
insert into t_vip(id,name,email)
values
(2,'zhangsan','[email protected]');
mysql> select * from t_vip;
+------+----------+------------------+
| id | name | email |
+------+----------+------------------+
| 1 | zhangsan | 295349478@qq.com |
+------+----------+------------------+
1 row in set (0.00 sec)
mysql> insert into t_vip(id,name,email)
-> values
-> (2,'zhangsan','[email protected]');
ERROR 1062 (23000): Duplicate entry 'zhangsan' for key 'name'
//其中name字段重复了,不可以插入,但是可以为null
设置两个字段联合唯一
//因为是两个字段联合唯一,如此只有当两个字段同时相同才会报错
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(32),
email varchar(255),
uique(name,email)
);
//name和email两个字段联合起来唯一!!!
约束直接添加到列后面的,叫列级约束。
约束没有添加在列的后面,这种约束称为表级约束。
什么时候使用表级约束?
需要给多个字段联合起来添加某一个约束的时候,需要使用表级约束。
主键约束:就是一种约束
主键字段:该字段删添加了主键约束,这样的字段叫做:主键字段
主键值:主键字段中的每一个值都叫做:主键值
什么是主键?有什么用?
主键是每一行记录的唯一标识。
注意:任何一张表都应该有主键,没有主键,表无效。
主键的特征:not null + unique (主键值不能是null,同时不能重复!)
drop table if exists t_vip;
//一个字段做主键交做:单一主键
create table t_vip(
id int primary key,
name varchar(32)
);
insert into t_vip(id,name) values(1,'zhansan');
insert into t_vip(id,name) values(2,'lisi');
insert into t_vip(id,name) values(2,'zhansan');
//不能重复
mysql> insert into t_vip(id,name) values(2,'zhansan');
ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
//不能为null
mysql> insert into t_vip(name) values('zhansan');
ERROR 1364 (HY000): Field 'id' doesn't have a default value
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(32),
primary key(id)
);
表级约束只要是给个多个字段联合起来添加约束
drop table if exists t_vip;
//id和name联合起来做主键:复合主键!!!
create table t_vip(
id int,
name varchar(32),
primary key(id,name)
);
//两个字段不能一起是null或者相同的时候
//一个表中主键约束只能有一个
在实际开发中不建议使用:复合主键。建议使用单一主键!
因为主键值存在的意义就是这行记录的身份证号,只要意义达到即可,单一主键可以做到!
主键值建议使用:
int
bigint
char
等类型。不建议使用:varchar来做主键。主键值一般都是数字,一般都是定长的。
主键除了:单一主键和复合主键之外,还可以这样进行分类?
在实际开发中使用自然主键比较多,因为主键只要做到不重复就行,不需要有意义。
业务主键不好,因为主键一旦和业务挂钩,那么当业务发生变动的时候,可能会影响到主键值,所以业务主键不建议使用。尽量使用自然主键。
在mysql中,有一种机制,可以帮助我们自动维护一个主键值
drop table if exists t_vip;
create table t_vip(
id int primary key auto_increment, //auto_increment表示自增,从1开始,以1递增
name varchar(32)
);
insert into t_vip(name) values('zhangsan');
insert into t_vip(name) values('zhangsan');
insert into t_vip(name) values('zhangsan');
insert into t_vip(name) values('zhangsan');
mysql> select * from t_vip;
+----+----------+
| id | name |
+----+----------+
| 1 | zhangsan |
| 2 | zhangsan |
| 3 | zhangsan |
| 4 | zhangsan |
+----+----------+
4 rows in set (0.00 sec)
//自增
外键约束涉及到的相关术语:
外键约束:一种约束
外键字段:改字段上添加了外键约束
外键值:外键字段当中的每一个值。
业务背景:
请书籍数据库表,来描述“班级和学生”的信息?
第一种方案:班级和学生存储在一张表中?
以上方案的缺点:
第二种方案:班级一张表,学生一张表?
注意:
t_class是父表,建的是父
t_student是子表,用的是子
删除表的顺序:先删子,后删父。
创建表的顺序:先创建父,再创建子。
删除数据的顺序:先删父,后删子。
插入数据的顺序:先插入父,再插入子。
drop table if exists t_student;
drop table if exists t_class;
create table t_class(
classno int primary key auto_increment,
classname varchar(32)
);
create table t_student(
no int primary key auto_increment,
name varchar(32),
cno int,
foreign key(cno) references t_class(classno)
);
insert into t_class(classno,classname) values(101,'科学城01');
insert into t_class(classno,classname) values(102,'科学城02');
insert into t_student(no,name,cno) values(1,'zhangsan',101);
insert into t_student(no,name,cno) values(2,'lisi',102);
select * from t_student;
select * from t_class;
思考:子表中的外键引用的父表中的某个字段,被引用的这个字段必须是主键吗?
不一定是主键,但是至少具有unique约束。也就是要唯一,不得话不知道引用的是父表的哪一行记录。
思考:外键可以为NULL吗?
可以为NULL
存储引擎是MySQL中特有的一个术语,其他数据库没有。(Oracle中有,但是不叫这个名字)
实际上存储引擎是一个表存储、组织数据的方式。
不同的存储引擎,表存储数据的方式不同。
//查看建表语句即可知道引擎
show create table t_student;
| t_student | CREATE TABLE `t_student` (
`no` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`cno` int(11) DEFAULT NULL,
PRIMARY KEY (`no`),
KEY `cno` (`cno`),
CONSTRAINT `t_student_ibfk_1` FOREIGN KEY (`cno`) REFERENCES `t_class` (`classno`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
由上可得建表的时候可以在最后小括号“ )”的右边使用:
没有指定则默认是InnoDB,字符编码为utf8
create table t_product(
id int primary key,
name varchar(32)
)engine=InnoDB default charset=utf8;
命令:show engines \G
*************************** 1. row ***************************
Engine: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
*************************** 2. row ***************************
Engine: MRG_MYISAM
Support: YES
Comment: Collection of identical MyISAM tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 3. row ***************************
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 4. row ***************************
Engine: BLACKHOLE
Support: YES
Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
XA: NO
Savepoints: NO
*************************** 5. row ***************************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 6. row ***************************
Engine: CSV
Support: YES
Comment: CSV storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 7. row ***************************
Engine: ARCHIVE
Support: YES
Comment: Archive storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 8. row ***************************
Engine: PERFORMANCE_SCHEMA
Support: YES
Comment: Performance Schema
Transactions: NO
XA: NO
Savepoints: NO
*************************** 9. row ***************************
Engine: FEDERATED
Support: NO
Comment: Federated MySQL storage engine
Transactions: NULL
XA: NULL
Savepoints: NULL
9 rows in set (0.00 sec)
mysql支持9大存储引擎,版本不同支持的情况也不同。
MyISAM存储引擎
它管理的表具有以下特征:
使用三个文件表示每个表:
提示:对于一张表来说,只要是主键,或者加油unique约束的字段上会自动创建索引。
优点:可以被转换为压缩、只读表来节省空间
MuisAM不支持事务机制,安全性低。
InnoDB存储引擎
mysql默认的存储引擎
InnoDB支持事务,支持数据库崩溃后自动恢复机制。
特点:非常安全
管理的表的主要特征:
最大的特点就是:支持事务,以保证数据的安全。所以效率是最高的,并且不能压缩,不能转换为只读,不能很好的节省存储空间。
MEMORY存储引擎
使用 MEMORY 存储引擎的表,其数据存储在内存中,且行的长度固定,
这两个特点使得 MEMORY 存储引擎非常快,但是断电及失。
MEMORY存储引擎管理的表具有下列特征:
MEMORY 存储一起被称为 HEAP 引擎。
优点:查询效率是最高的。
缺点:不安全,关机之后数据消失。因为数据和索引都是在内存当中。
一个事务其实就是一个完整的业务逻辑。
是一个最小的工作单元。不可再分。
什么是一个完整的业务逻辑?
假设转账,从A账户向B账户中转账10000.
将A账户的钱减去10000(update语句)
将B账户的钱加上10000(update语句)
这是一个完整的业务逻辑。
以上的操作是一个最小的工作单元,要么同时成功,要么同时失败,不可再分。
这两个update语句要求必须同时成功或者同时失败,这样才能保证钱是正确的、
可以认为最小的业务逻辑,一定涉及到两条数据库增删改操作,而这也是最小的事务
insert
delete
update
只有以上的三个语句和事务有关系,其它都没有关系。
因为只有以上的三个语句是数据库表中数据进行增、删、改的。
只要你的操作一旦涉及到数据的增、删、改,那么就一定要考虑安全问题、
数据安全第一位!!
存在事务的根本原因:一条语句不能完成一件事的时候我们就需要事务的存在。
所以这种假设不需要。
到底什么是事务?
一个事务其实就是多条DML语句同时成功,或者同时失败。
(一如计算机的01,我们不能容忍成功一半的事务)
事务:就是批量的DML语句同时成功,或者同时失败。
InnoDB存储引擎:提供一组用来记录事务性活动的日志文件
//事务开启了
insert
insert
insert
delete
update
//事务结束了
在事务的执行过程中,每一个DML的操作都会记录到“事务性活动的日志文件”中
在事务的执行过程中,我们可以提交事务,也可以回滚事务。
提交事务?
清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中。
提交事务标志着,事务的结束。并且是一种全部成功的结束。
回滚事务?
将之前所有的DML操作全部撤销,并且清空事务性活动的日志文件。
回滚事务标志着,事务的结束。并且是一种全部失败的结束。
提交事务:commit;语句
回滚事务:rollback;语句(回滚永远都是只能回滚到上一次的提交点!)
事务对应的英语单词:transaction
测试一下,在mysql中默认的事务行为是怎样的?
mysql默认情况下是支持自动提交事务的。(自动提交)
是么是自动提交?
每执行一条DML语句,则提交一次!
这种自动提交实际上是不符合我们的开发习惯,因为一个业务通常是需要多条DML语句共同执行才能完成的,为了保证数据的安全,必须要求同时成功之后再提交,所以不能执行一条就提交一条。
关闭自动提交机制并回滚rollbanck
怎么将mysql的自动提交机制关闭掉呢?
//执行命令:start transaction;
mysql> select * from t_vip;
+----+----------+
| id | name |
+----+----------+
| 1 | zhangsan |
| 2 | zhangsan |
| 3 | zhangsan |
| 4 | zhangsan |
+----+----------+
4 rows in set (0.05 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from t_vip;
Query OK, 4 rows affected (0.00 sec)
mysql> select * from t_vip;
Empty set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.06 sec)
mysql> select * from t_vip;
+----+----------+
| id | name |
+----+----------+
| 1 | zhangsan |
| 2 | zhangsan |
| 3 | zhangsan |
| 4 | zhangsan |
+----+----------+
4 rows in set (0.00 sec)
每次执行数据库操作都会将操作放到活动日志中,并提交。
关闭自动提交机制,则会将操作放到活动日志中当不提交,日志提交则数据库操作不能更改。
提交commit
mysql> select * from t_vip;
+----+----------+
| id | name |
+----+----------+
| 1 | zhangsan |
| 2 | zhangsan |
| 3 | zhangsan |
| 4 | zhangsan |
+----+----------+
4 rows in set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from t_vip;
Query OK, 4 rows affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.06 sec)
mysql> select * from t_vip;
Empty set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_vip;
Empty set (0.00 sec)
当提交commit的时候就不能再回滚。
所有的DML操作都会进入活动日志中,默认操作一次提交一次,可以关闭提交,手动提交。只要活动日志中存在就可以回滚,而回滚就是将活动日志反向一次。
A教室和B教室中间有一道墙,这墙可以很厚,也可以很薄。这就是事务的隔离级别。
事务和事务之间的隔离级别有4个级别!
验证:read uncommited
验证:read commited
验证:repeatable read
验证:serializable
索引是在数据库表的字段上添加的,是为了提高查询效率存在的一种机制。
一张表的一个字段可以添加一个索引,当然,多个字段联合起来也可以添加索引。
索引相当于一本书的目录,是为了缩小扫描范围而存在的一种机制。
对于一本字典来说,查找某个汉字有两种方式:
第一种方式:一页一页挨着找,知道找到为止,这种查找方式属于全字典扫描,效率较低。
第二种方式:先通过目录(索引)去定位一个大概的位置,然后直接定位到这个位置,做全局扫描,缩小扫描的范围,快速的查找。这种查找方式属于通过索引检索,效率较高。
索引要排序,并且这个索引的排序和 TreeSet(TreeMap) 数据结构相同。 TreeSet(TreeMap) 底层是一个自平衡的二叉树
在mysql当中索引是一个 B-Tree 数据结构
遵从左小右大原则存放,采用中序遍历方式遍历取数据。
假设有一张用户表:t_user
id(PK) name 每一行记录在硬盘上都有物理存储编号
----------------------------------------------------------------
100 zhangsan 0x134546
101 zhangsan1
102 zhangsan2
103 zhangsan3
提醒1:在任何数据库当中主键上都会自动添加上索引对象,id字段上自动有索引,因为id是PK。另外在mysql当中,一个字段上如果有unique约束的话,也会自动创建索引对象。
提醒2:在任何数据库当中,任何一张表的任何一条记录在硬盘存储上都有一个硬盘的物理存储编号。
提醒3:在mysql当中,索引是一个单独的对象,不同的存储引擎以不同的形式存在,在MyISAM存储引擎中,索引存储在一个.MYI文件中。在InnoDB存储引擎中索引存储在一个逻辑名称叫做tablespace当中。在MEMORY存储引擎当中索引被存储在内存当中。不管索引存储在哪里,索引在mysql当中都是一个树的形式存在。(自平衡二叉树:B-Tree)
索引的实现原理:就是缩小扫描的范围,避免全表扫描
对于数据库来说查找操作是最多的
索引其实就是对一个字段标记,然后将 标记字段的记录 和 物理地址 拿出来做成自平衡二叉树方便查找。
就是将没有目的的查找变成有方法的查找
什么条件下,我们会考虑给字段添加索引呢?
条件1:数据量庞大(到底有多么庞大算庞大,这个要测试,每一个硬件条件不同)
条件2:改字段经常出现在where的后面,以条件的形式存在,也就是说这个字段总是被扫描(用来定位的字段)
条件3:改字段很少的DML操作。(因为DML之后,索引需要重新排序)
建议不要随意添加索引,因为索引也是需要维护的,太多的索引反而会家底系统的性能。
建议通过主键查询,建议通过unique约束的字段进行查询,效率是比较高的。
创建索引:
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.08 sec)
mysql> create index emp_ename_index on emp(ename);
给emp表的ename字段添加索引,起名:emp_ename_index
删除索引:
mysql> drop index emp_ename_index on emp;
将emp表上的emp_ename_index索引对象删除
使用explain解释语句:
未使用索引
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AqDCFIBt-1633507453365)(D:\Program Files\MySql_study\MySql.assets\image-20211004151303218.png)]
其中可以看到rows是14,表示查询了14次,type使用的是ALL
使用索引:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9M3BYgaY-1633507453367)(D:\Program Files\MySql_study\MySql.assets\image-20211004151320830.png)]
rows一条,type方式上面也说了ref
数组 + 树的结合体
1、模糊查询以 % 看开头
select * from emp from ename like '%T';
ename上即使添加了索引,也不会走索引:因为模糊匹配当中以 “ % ” 开头
尽量避免模糊查询的时候以 “ % ” 开始。
这是一种优化的手段
2、使用or的时候一个条件不是索引字段的时候
select * from emp from ename = 'KING' or job = 'MANAGER';
如果使用or,那么要求or两边的条件字段都要有索引,才会走索引,如果其中一边有一个字段没有索引,那么另一个字段上的索引也会失效。所以不建议使用or,建议使用union合并查询结果。
3、使用复合索引的时候,没有使用左侧的列查找
什么是复合索引?
两个字段,或者更多的字段联合起来添加一个索引,叫做复合索引。
create index emp_job_sal_index on emp(job,sal);
explain select * from emp where job = 'MANAGER';
explain select * from emp where sal = 800; //索引失效
drop index emp_job_sal_index on emp;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R29VZxBu-1633507453368)(D:\Program Files\MySql_study\MySql.assets\image-20211004155528052.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6wQu8EhS-1633507453371)(D:\Program Files\MySql_study\MySql.assets\image-20211004155635068.png)]
4、在where当中索引列参加了运算
create index emp_sal_index on emp(sal);
未参加运算的情况下:
explain select * from emp where sal = 800;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IVGKD31H-1633507453373)(D:\Program Files\MySql_study\MySql.assets\image-20211004160002891.png)]
参加运算的情况下(失效):
explain select * from emp where sal*2 = 400;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-prLtF7Lx-1633507453374)(D:\Program Files\MySql_study\MySql.assets\image-20211004160105439.png)]
一定是索引列,索引等号后面不会失效。
5、在where当中索引列使用了函数
explain select * from emp where lower(ename) = 'smith';
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W8ctR8z2-1633507453375)(D:\Program Files\MySql_study\MySql.assets\image-20211004160308958.png)]
where中的索引列不要使用函数和运算
优化的时候优先考虑的因素就是索引。
索引在数据库当中分很多的类:
单一索引:一个字段上添加索引
复合索引:两个字段或者更多的字段上添加索引。
主键索引:主键上添加索引
唯一性索引:具有unique约束的字段上添加索引
…
注意:唯一性比较弱的字段上添加索引用处不大。
view:站在不同的角度取看待同一份数据。
表复制:
create table dept2 as select * from dept;
dept2表中的数据:
mysql> select * from dept2;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
4 rows in set (0.00 sec)
创建视图对象:
create view dept2_view as select * from dept2;
删除视图对象:
drop view dept2_view;
注意:只有DQL语句才可以view的形式创建。
create view view_name as 这里的语句必须是DQL语句;
我们可以面向视图对象进行增删查改,对视图对象的增删改查,会导致原表被操作。(视图的特点:通过对视图的操作,会影响到原表数据。)
//面向视图查询
select * from dept2_view;
insert into dept2_view(deptno,dname,loc) values(60,'SALES','BEIJING');
mysql> create view dept2_view as select * from dept2;
Query OK, 0 rows affected (0.13 sec)
//面向视图查询
mysql> select * from dept2_view;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
4 rows in set (0.00 sec)
//面向视图插入
mysql> insert into dept2_view(deptno,dname,loc) values(60,'SALES','BEIJING');
Query OK, 1 row affected (0.06 sec)
//面向视图查询
mysql> select * from dept2_view;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
| 60 | SALES | BEIJING |
+--------+------------+----------+
5 rows in set (0.00 sec)
//面向原表查询
mysql> select * from dept2;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
| 60 | SALES | BEIJING |
+--------+------------+----------+
5 rows in set (0.00 sec)
mysql> delete from dept2_view;
Query OK, 5 rows affected (0.05 sec)
mysql> select * from dept2;
Empty set (0.00 sec)
对视图对象数据的DML操作会影响到原表的数据,视图可以对原表进行过滤,然后对过滤后的数据进行操作。
多张表的视图也可以进行数据过滤
多表的视图
create table emp2 as select * from emp;
create table dept2 as select * from dept;
//创建emp2,dept2的视图对象
create view emp_dept_view as
select e.ename,e.sal,d.dname
from emp2 e
join dept2 d
on e.deptno = d.deptno;
//面向视图对象查询
mysql> select * from emp_dept_view;
+--------+---------+------------+
| ename | sal | dname |
+--------+---------+------------+
| SMITH | 800.00 | RESEARCH |
| ALLEN | 1600.00 | SALES |
| WARD | 1250.00 | SALES |
| JONES | 2975.00 | RESEARCH |
| MARTIN | 1250.00 | SALES |
| BLAKE | 2850.00 | SALES |
| CLARK | 2450.00 | ACCOUNTING |
| SCOTT | 3000.00 | RESEARCH |
| KING | 5000.00 | ACCOUNTING |
| TURNER | 1500.00 | SALES |
| ADAMS | 1100.00 | RESEARCH |
| JAMES | 950.00 | SALES |
| FORD | 3000.00 | RESEARCH |
| MILLER | 1300.00 | ACCOUNTING |
+--------+---------+------------+
14 rows in set (0.00 sec)
//面向视图更新
update emp_dept_view set sal = 1000 where dname = 'ACCOUNTING';
//面向视图对象查询
mysql> select * from emp_dept_view;
+--------+---------+------------+
| ename | sal | dname |
+--------+---------+------------+
| SMITH | 800.00 | RESEARCH |
| ALLEN | 1600.00 | SALES |
| WARD | 1250.00 | SALES |
| JONES | 2975.00 | RESEARCH |
| MARTIN | 1250.00 | SALES |
| BLAKE | 2850.00 | SALES |
| CLARK | 1000.00 | ACCOUNTING |
| SCOTT | 3000.00 | RESEARCH |
| KING | 1000.00 | ACCOUNTING |
| TURNER | 1500.00 | SALES |
| ADAMS | 1100.00 | RESEARCH |
| JAMES | 950.00 | SALES |
| FORD | 3000.00 | RESEARCH |
| MILLER | 1000.00 | ACCOUNTING |
+--------+---------+------------+
//查看emp2,dept2原表数据
mysql> select * from emp2;
+-------+--------+-----------+------+------------+---------+---------+--------+
| 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 | 1000.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 1000.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 | 1000.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
14 rows in set (0.00 sec)
(方便,简化开发,利于维护)
有时需要多次使用多表连接后的数据,而多表连接的sql可能要很长很长,这时就要使用视图,将连接的数据先暂时变成表(其实是视图)。
注意:视图对应的语句只能是DQL语句
但是视图对象创建完成之后,可以对视图进行增删查改等操作
重点掌握:数据的导入和导出(数据的备份)
其他命令了解即可
create user zhangpenghui identified by '123456';
导出整个数据库
在windows 的dos 命令窗口执行:
//导出所有的表
mysqldump 数据库名称>数据库导出位置以及导出文件名称 -u数据库账号 -p数据库密码
mysqldump bjpowernode>D:\bjpowernode.sql -uroot -p123456
//导出指定的表
mysqldump 数据库名称 数据库中指定的表>数据库导出位置以及导出文件名称 -u数据库账号 -p数据库密码
mysqldump bjpowernode emp>D:\bjpowernode.sql -uroot -p123456
导入整个数据库
注意:需要先登录到mysql数据库服务器上。
数据库表的设计依据。教你怎么进行数据库表的设计。
一共有三个
设计数据库表的时候,按照以上范式进行,可以避免表中数据的荣誉,空间的浪费、
最核心,最重要的范式,所有表的设计都需要满足。
必须有主键,并且每一个字段都是原子性不可再分。
字段可不可以在分
建立在第一范式的基础上
要求所有非主键字段完全依赖主键,不要尝产生部分依赖。
只有一种情况下:复合主键:在第一范式的基础上,产生复合主键,就可能不符合第二范式
不符合第二范式:会造成数据冗余
如果是多对多关系,那么将一张表变成两张表,再加多一张表来表示他们的联系关系
而关系表要使用外键
多对多关系,走3表,关系上外键。
建立在第二范式的基础上
要求所有非主键字段直接依赖主键,不要产生传递依赖。
表可不可以再分:可以再分表示:非主键字段不是直接依赖主键
每个字段完全靠主键表示
非主键字段是否可以依赖于依赖别的非主键字段
不符合第三范式:会造成数据冗余
一对多关系,走2表,多上外键。
表与表的连接次数越多,效率越低。(笛卡尔积)
有时会用冗余换执行速度