MySQL
* Sql语句分类
-
DQL:数据查询语言(带有select的都是DQL)
-
DML:数据操作语言(凡是对表中数据进行修改的都是DML)
如 insert delete update(增删改)
-
DDL :数据定义语言(带有create drop alter 都是DDL)
主要操作的是表的结构,而不是表的数据
create 新建,等同于增
dorp 删除
alter 修改
这边的增删改和DML不同,这个主要是对表进行操作
-
TCL:事物控制语言,包括:
事物提交:commit
事物回滚:rollback
-
DCL:数据控制语言,如授权grant,撤销权限revoke
* 查看表
- 查看表结构
desc 表名称
- 查看表数据
select * from 表名称
* 终止一条命令输入
\c
* 退出
exit
* 简单查询
注意,在执行查询等操作之前,要首先use一个数据库,不然无法进行
- 查询一个字段
select 字段名 from 表名;
- 查询多个字段
使用逗号隔开字段名即可
select 字段1,字段2 from 表名;
- 查询所有元素
select * from 表名;
缺点:效率低,可读性差,开发中最好不用 * 来查询,主要是自己快速查看全表数据时使用。
- 给查询的列起别名
+ as 关键字
as 关键字,只会修改显示时的名称,不会修改数据名称
select deptno,dname as deptname from dept;
注意! as 关键字可以省略,上述代码可以写为:
select deptno,dname deptname from dept;
效果相同。
+ 别名规范
别名内不能有空格,如果要在别名中写空格,需要使用单引号将别名包裹起来,在mysql中也可以使用双引号进行包裹,都是在oracle中不能使用双引号。
注意,别名可以使用汉字取,但是需要给别名加上单引号
- 查询时计算字段
在字段中可以使用数学表达式,如下:
select sal*12 as yearMoney,ename from emp;
* 条件查询
条件查询是使用到where语句,where必须放在from语句的后方
条件查询支持的运算符
- 等号操作符
查询表中与所给元素相等的条目
语法格式:
select … from … where 条件;
select empno,ename,sal from emp where sal = 5000;
select empno,ename,sal from emp where job = "manager";
# 注意,此处使用双引号也可
+ 大小写规范
- 数据库和名和表名是严格区分大小写的
- 表的别名严格区分大小写
- 列名与列的别名在所有的情况下军事忽略大小写
- 变量名也是严格区分大小写的:MySQL在window下都不区分大小写
- <>操作符
<>不止可以比大小,还可以表示不等号
大小号操作符还包括:
< , > , <= , >=
- between … and …
表示查询某个值在规定范围之间,该范围必须是左小右大的形式。
between等同于 >= and <=
select ename,sal from emp where sal between 0 and 10000;
- null
判断某个元素是否为空,可以使用 is null,不能使用 = null
判断某个元素是否不为空,可以使用 is not null
- and
表示并且,可以进行多条件查询,如下:
select ename,sal from emp where job = 'manager'and sal > 2500;
- or
表示或者,即为可以为一个字段匹配到多个元素
# 查询工作为manager和salesman的员工
select ename,sal,job from emp where job = 'manager'or 'salesman';
- 表达式的优先级
注意:运算符可以使用括号
-
错误的查询写法
查询薪水大于 1800,并且部门代码为20 或 30 的员工
select * from emp where sal>1800 and deptno = 20 or deptno = 30;
-
正确的查询写法
查询薪水大于 1800,并且部门代码为20 或 30 的
select * from emp where sal>1800 and (deptno = 20 or deptno = 30);
- in
in表示包含的意思,完全可以采用or表示,但是采用in会更加简洁一些
select * from emp where job in ('manager','salesman');
select * from emp where sal in(1000,3000);
- not
表示不是,在mysql中表示否定的词汇即为not,符号有<>
# 使用not来表示否定
select * from emp where sal not in(1600,3000);
# 使用<>来表示否定
select * from emp where sal<>1600 and sal <> 3000;
- like
like可以实现模糊查询
支持%和下划线_匹配
注意:%在mysql中表示任意多且任意的字符,_在mysql中表示任意一个字符
注意,like中的表达式必须放在单引号或者是双引号之中
# 查询名字第二个字符为A的所有员工
select * from emp where ename like'_A%';
# 查询名字以M开头的所有员工
select * from emp where ename like 'M%';
# 查询姓名中包含O的所有员工
select * from emp where ename like '%O%';
* 排序数据
- 排序采用的是order by子句
- 在 order by 后根上排序字段
- 排序字段可以放多个元素,多个中采用逗号间隔
- order by默认采用升序排序(即为从小到大排序)
- 如果存在where语句,那么order by 语句需要在where语句的后方
- 注意:对于字符串的排序都是根据字符串首字母按照字母表的顺序进行排序
# 查询对员工工资按照升序进行排序的员工数据
select * from emp order by sal;
# 查询所有job为manager的员工按照工资升序排序的数据
select * from emp where job = 'manager'order by sal;
- 手动制定排序方式
+ 手动指定升序排序(ASC)
升序排序即为从小到大排序
升序排序是默认排序,一般情况下不需要手动指定
select * from emp order by sal asc;
+ 手动指定降序排序(DESC)
降序排序即为从大到小排序
# 对所有员工按照员工工资进行降序排序
select * from emp order by sal desc;
- 多个字段排序
多个字段排序即为在order by之后可以跟上多个排序要求,多个排序要求之间使用逗号连接
# 按照job和sal倒序排序
select * from emp order by job desc,sal desc;
+ 多字段排序规则:
- 多字段排序是按照条件的优先级进行排序,优先满足靠近order by 语句的条件
- 多字段排序中如果第一个排序元素重复,那么就会按照第二个条件进行排序
- 多字段排序中的字符串同样是字符串首字母按照字母表进行排序
- 通过字段位置进行排序
通过字段位置进行排序就是说在order by条件的位置写上一个数字,该数字一般情况下表示表中数据的位置,但是不建议使用,因为数字表示的含义不明确,程序不健壮
# 要按照工资进行排序,由于sal在所有元素怒中的位置是第六位,所以使用order by 6
select * from emp order by 6;
* 综合案例1
找出工资在1250到3000之间的员工信息,要求薪资降序排序
select * from emp where sal between 1250 and 3000 order by sal desc;
* 数据处理函数/单行处理函数
- lower
lower即为将指定列的字符串转换为小写形式输出
注意:lower要将要转化为小写的元素使用()包裹起来
select lower(ename) from emp;
- upper
和lower类似,是将指定列的字符串转化为大写字母输出
同样需要将要转化的元素使用()进行包裹
select upper(ename) from emp;
- substr
能够起到截取指定长度进行查询的效果
如下:
# 查询所有首字母为大写M的员工姓名
select * from emp where substr(ename,1,1) = upper('m');
注意:
- 在substr中,可以传入三个参数,第一个参数为要截取的字符串
- 第二个为截取字符串的开头,最小值为1,即为mysql中字符串的索引为从1开始
- 第三个值为取值长度,即为从所给的字符串开头向后取多长的字符串
select substr(ename,2,4) from emp;
- concat
concat能够进行字符串的拼接
select concat(empno,ename) from emp;
- length
length即为取得字符串的长度,可以用于判断等
同样,length也需要将元素使用()进行包裹
select length(ename),ename from emp;
- trim
trim会去除首尾的空格,但是不会去除字符串中间的空格
如果在输入的数据中包含头尾空格,正常情况下不去除空格是无法进行查询的,因此需要使用trim进行去除头尾空格进行查询
select * from emp where job = trim(upper(' manager '));
- str_to_date(必须严格按照标准输出)
常规查询日期(由于该日期格式和mysql日期格式相同,所以可以直接查询)
select * from emp where HIREDATE = '1981-02-20';
如果给定的字符串中不按照mysql的日期格式存放数据,那么就可以使用str_to_date将字符串转化为date类型进行输出
# 如下,该日期是不按照mysql的日期格式进行编写的,所以需要使用str_to_date方法将该字符串转化为符合mysql中的date格式
select * from emp where HIREDATE=str_to_date('02-20-1981','%m-%d-%Y');
- date_format
使用date_format能够将日期格式化为yyyy-mm-dd hh:mm:ss
select empno, ename, date_format(hiredate, '%Y-%m-%d %H:%i:%s') as hiredate from emp;
+ 查询当前时间的年月日时分秒
select date_format(now(),'%Y-%m-%d %H %i %s');
+ 日期格式
%Y:代表 4 位的年份
%y:代表 2 位的年份
38 / 103
%m:代表月, 格式为(01……12)
%c:代表月, 格式为(1……12)
%H:代表小时,格式为(00……23)
%h: 代表小时,格式为(01……12)
%i: 代表分钟, 格式为(00……59)
%r:代表 时间,格式为 12 小时(hh:mm:ss [AP]M)
%T:代表 时间,格式为 24 小时(hh:mm:ss)
%S:代表 秒,格式为(00……59)
%s:代表 秒,格式为(00……59)
- format
-
format属于日期函数,在mysql中是数据内容格式化的,格式化后结果为:XXX,XXX,XXX. 即为三位三位的,称为千分位
-
format可以传入两个参数,第一个参数是要转化为千分位的列,第二个参数是小数位的位数,如果不准备显示小数位,就写0.
# 查询员工薪水并以千分位格式输出
select empno, ename, Format(sal, 0) from emp;
# 查询员工薪水加入千分位并且保留两位小数
select empno, ename, Format(sal, 2) from emp;
- round
对含小数的数值进行四舍五入
有两种传参类型
- 直接传入数值
select round(123.4213);
# 得到123
select round(123.532);
# 得到124
-
传入数值和一个数
第一个数值即为要转化的数,第二个值为要保留几位小数
select round(123.264,2);
保留到十位,百位等,则需要在第二个数的位置填入-1,-2等
select round(1236.567, -1) as result from emp; // 保留到十位。
- rand
能够生成随机数
select rand();
随机抽取记录数
select * from emp order by rand() limit 2;
生成100以内的随机整数
select round(rand()*100,0) from emp;
+ limit
limit的作用是限制查询的条数
上方的limit 2 即为排序完成之后只查询两条消息
- case … when … then ……else …end
(注意:不修改数据库,只是将查询结果显示为工资上调)
# 将sal数值按照不同类型的工作进行增长
select empno, ename, job, sal, case job when 'MANAGER' then sal*1.1 when 'SALESMAN' then sal*1.5 end as newsal from emp;
# 其他的工资不动,需要添加 else
select e.*,sal ,case job when 'salesman' then sal*1.1 when 'clerk' then sal*1.2 else sal end as new_sal from emp e;
- ifNull
-
如果NULL参与运算,那结果一定为null,为了避免出现有null而影响计算结果的情况,外面可以使用ifNull函数传入两个参数
-
第一个参数为可能包含null值的列名,第二个为如果出现了null自己想要设置的替换值
-
ifNull的用处即为如果在计算过程中遇到了NULL值,就使用替换值将其替换,如果不为null就使用本身的值进行计算
* 分组函数/ 聚合函数/ 多行 处理函数
多行处理函数的特点:输入多行,最终输出一行。
- 分组函数的使用
找出最高工资?
mysql> select max(sal) from emp;
找出最低工资?
mysql> select min(sal) from emp;
计算工资和:
mysql> select sum(sal) from emp;
计算平均工资:
mysql> select avg(sal) from emp;
计算员工数量?
mysql> select count(ename) from emp;
- 分组函数使用注意事项
分组函数自动忽略空值,不需要手动的加where 条件排除空值。
select count(*) from emp where xxx; 符合条件的所有记录总数。
select count(comm) from emp; comm 这个字段中不为空的元素总数。
分组函数不能直接使用在where 关键字后面。
select ename,sal from emp where sal > avg(sal);
ERROR 1111 (HY000): Invalid use of group function
分组函数自动忽略NULL,你不需要提前对NULL进行处理。
因为自动忽略NULL,所以不用担心在计算和时会受到NULL的影响
分组函数中count(*)和count(具体字段)有什么区别?
count(*)表示的是计算当前表中的总行数
count(字段名)表示的是计算该字段下不为NULL的元素怒的总和
分组函数不能够直接使用在where子句中。
#下方这一行查询语句是会报错的,因为在where语句中不能使用分组函数
select ename,sal from emp where sal > min(sal);
所有的分组函数可以组合起来一起用。
得到emp表内的所有分组函数的值
select sum(sal),min(sal),max(sal),avg(sal),count(*) from emp;
* 分组查询(重点)
- 分组查询顺序
mysql的查询关键字顺序为:
1.from 2. where 3. group by 4. select 5. order by
注意:select是在group by之后执行的,所以是先分组然后才select的
因为分组函数在使用的时候必须先分组之后才能使用,不能直接使用在where后面.
- 分组查询例子
# 找出部门的最高薪资
select deptno,max(sal) from emp group by deptno;
# 找出“每个部门,不同工作岗位”的最高薪资?
select job,max(sal),deptno from emp group by deptno,job;
* having
- 使用having可以对分完组之后的数据进一步过滤。
- having不能单独使用,having不能代替where,having必须和group by联合使用。
# 找出每个部门最高薪资,要求显示最高薪资大于3000的?
select deptno,max(sal) from emp group by deptno having max(sal)>3000;
# 由于这种方式执行效率低,本题还有另外一种解法
select deptno,max(sal) from emp where sal>3000 group by deptno;
where和having,优先选择where,where实在完成不了了,再选择having。
# 找出每个部门平均薪资,要求显示平均薪资高于2500的。
select deptno,avg(sal) from emp group by deptno having avg(sal)>2500;
* 综合案例2
找出每个岗位的平均薪资,要求显示平均薪资大于1500的,除MANAGER岗位之外,要求按照平均薪资降序排。
select job, avg(sal) as avgsal from emp where job <> 'MANAGER' group by job having avg(sal) > 1500 order by avgsal desc;
* 关键字顺序
from
where
group by
having
select
order by
* distinct关键字
去除重复记录
select distinct job from emp;
注意,要关注去重之后剩下的记录数,如果一个属性剩下的记录数与其他属性不相同,那么就会出错
select ename,distinct job from emp;
因此:distinct只能写在所有字段的最前方,这种情况下是将所有字段重复的综合情况进行去重
* 连接查询(多表查询)
连接查询:也可以叫跨表查询,需要关联多个表进行查询
- 表连接方式分类
-
内连接
- 等值连接
- 非等值连接
-
外连接
- 左外连接
- 右外连接
-
全连接
- 笛卡尔积现象
多张表连接查询时无条件限制,最终查询结果为多张表条数的乘积
+ 避免笛卡尔积现象
添加条件进行筛选
- 内连接
+ 等值连接
` SQL92语法
将不同表的某个相同字段通过等号进行匹配,从而达到筛选的目的
#以下即为通过部门编号进行筛选,从而查询到每个员工所在的部门名称。
select
e.ename,d.dname
from
emp e, dept d
where
e.deptno = d.deptno;
sql92的缺点:结构不清晰,表的连接条件,和后期进一步筛选的条件,都放到了where后面。
` SQL99语法
语法结构:
select
...
from
a
join
b
on
a和b的连接条件
where
筛选条件
使用join关键字进行内连接查询,结构更加清晰明了
select
e.ename,d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno;
除此之外,还可以添加inner关键字,增加可读性,一眼就可以看出来这是内连接,但是inner可以省略
select
e.ename,d.dname
from
emp e
inner join
dept d
on
e.deptno = d.deptno;
sql99优点:表连接的条件是独立的,连接之后,如果还需要进一步筛选,再往后继续添加where
+ 非等值连接
非等值即为通过判断大小以及判断范围等进行筛选数据
# 找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级?
select e.ename, e.sal, s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal;
+ 自连接
技巧就是将一张表当作两张表来使用,如下的将emp分为表a和表b进行筛选
# 查询员工的上级领导,要求显示员工名和对应的领导名
select
a.ename as '员工名', b.ename as '领导名'
from
emp a
join
emp b
on
a.mgr = b.empno;#员工的领导编号 = 领导的员工编号
- 外连接
注意,在内连接中两张表是平等的,而在外连接中分为了主表和次表
+ 右外连接
包含关键字right join和outer,right代表着将join关键字右边的表作为主表,主要是为了将这张表的数据全部查询出来,捎带着关联查询左边的表
# 查询每个员工的部门名称
select
e.ename,d.dname
from
emp e
right join
dept d
on
e.deptno = d.deptno;
注意,outer关键字同样可以省略,但是也可以加上,这样可读性更强,一眼就可以看出来是外连接
# 查询每个员工的部门名称
select
e.ename,d.dname
from
dept d
left outer join
emp e
on
e.deptno = d.deptno;
注意:外连接的查询条数一定会大于等于内连接查询条数
# 查询每个员工的上级领导
select
a.ename as '员工名', b.ename as '领导名'
from
emp a
left join
emp b
on
a.mgr = b.empno;
` 多表查询语法
select
...
from
a
join
b
on
a和b的连接条件
join
c
on
a和c的连接条件
right join
d
on
a和d的连接条件
注意:有一条SQL中内连接和外连接可以混合出现
# 找出每个员工的部门名称以及工资等级,要求显示员工名、部门名、薪资、薪资等级
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;
* 子查询
子查询指的是select语句中嵌套select语句,被嵌套的select语句称为子查询。
- 语法
select
..(select).
from
..(select).
where
..(select).
# 找出比最低工资高的员工姓名和工资
# 如果说直接在where内使用分组函数,肯定会报错,就如以下查询语句:
select
ename,sal
from
emp
where
sal > min(sal);
#那么要实现该查询,就需要使用到子查询,先找最低工资,再找工资大于800的,最后合并
select ename,sal from emp where sal > (select min(sal) from emp);
- from语句中的子查询
from后面的子查询,可以将子查询的查询结果当做一张临时表。
# 找出每个岗位的平均工资的薪资等级。
#第一步:找出每个岗位的平均工资(按照岗位分组求平均值)
select job,avg(sal) from emp group by job;
#第二步:克服心理障碍,把以上的查询结果就当做一张真实存在的表t。
mysql> select * from salgrade;
#t表和s表进行表连接,条件:t表avg(sal) between s.losal and s.hisal;
select
t.*, s.grade
from
(select job,avg(sal) as avgsal from emp group by job) t
join
salgrade s
on
t.avgsal between s.losal and s.hisal;
* select 后出现的子查询
# 查出每个员工的部门名称,显示出员工们名和部门名
SELECT e.ename,e.deptno,(SELECT d.dname FROM dept d WHERE e.deptno = d.deptno)AS dname FROM emp e;
#对于select后面的子查询来说,这个子查询一次只能返回一条结果,多于一条就会报错
select e.ename,e.deptno,(select dname from dept)as dname from emp e;
下方第一条为查询员工名称和部门编号,第二条是查询部门名称
* union合并查询结果集
#查询工作岗位是MANAGER和SALESMAN的员工
SELECT ename,job FROM emp WHERE job = 'manager' OR job = 'salesman';
#也可以是
SELECT ename,job FROM emp WHERE job IN('manager','salesman');
union的作用:对于表连接操作,union的效率要高一些,对于传统的表连接操作,由于笛卡尔积的效应,常规的表拼接是乘法匹配,而union可以将乘法变为加法
a 连接 b一个结果:10 * 10 --> 100次
a 连接 c一个结果:10 * 10 --> 100次
使用union的话是:100次 + 100次 = 200次。(union把乘法变成了加法运算)
- union注意事项
+ union结果集列数要相同
select ename,job from emp where job = 'MANAGER'
union
select ename from emp where job = 'SALESMAN';
+ 列和列的数据类型也要一致
select ename,job from emp where job = 'MANAGER'
union
select ename,sal from emp where job = 'SALESMAN';
* limit
- 作用
- 将查询结果集的一部分取出来。通常使用在分页查询当中。
- 百度默认:一页显示10条记录。
- 分页的作用是为了提高用户的体验,因为一次全部都查出来,用户体验差。
- 可以一页一页翻页看。
- 用法
+ 用法1
limit startIndex, length
startIndex是起始下标,length是长度。
起始下标从0开始。
#这是取前五
select
ename,sal
from
emp
order by
sal desc
limit 0,5;
+ 用法2
limit 5;
这是取前5
select
ename,sal
from
emp
order by
sal desc
limit 5;
- limit在order by之后执行
- 取出工资排名在【3-5】名的员工
SELECT ename,sal FROM emp ORDER BY sal DESC LIMIT 2,3;
- 取出工资排名在【5-9】名的员工
SELECT ename,sal FROM emp ORDER BY sal DESC LIMIT 4,5;
- 分页(包含分页公式)
每页显示三条记录
第1页:limit 0,3 [0 1 2]
第2页:limit 3,3 [3 4 5]
第3页:limit 6,3 [6 7 8]
第4页:limit 9,3 [9 10 11]
每页显示pageSize条记录
第pageNo页:limit (pageNo - 1) * pageSize , pageSize
* DQL语句大总结
执行顺序?
1.from
2.where
3.group by
4.having
5.select
6.order by
7.limit..
* 表的创建(DDL:create drop alter)
- 创建表语法
create table 表名(字段名1 数据类型, 字段名2 数据类型, 字段名3 数据类型);
create table 表名(
字段名1 数据类型,
字段名2 数据类型,
字段名3 数据类型
);
表名:建议以t_ 或者 tbl_开始,可读性强。见名知意。
字段名:见名知意。
表名和字段名都属于标识符。
- mysql中数据类型
+ varchar
varchar(最长255)
可变长度的字符串
比较智能,节省空间。
会根据实际的数据长度动态分配空间。
优点:节省空间
缺点:需要动态分配空间,速度慢。
+ char
char(最长255)
定长字符串
不管实际的数据长度是多少。
分配固定长度的空间去存储数据。
使用不恰当的时候,可能会导致空间的浪费。
优点:不需要动态分配空间,速度快。
缺点:使用不当可能会导致空间的浪费。
+ varchar和char怎么选择
性别字段你选什么?因为性别是固定长度的字符串,所以选择char。
姓名字段你选什么?每一个人的名字长度不同,所以选择varchar。
+ int
数字中的整数型。等同于java的int。
+ bigint
数字中的长整型。等同于java中的long。
+ float
单精度浮点型数据
+ double
双精度浮点型数据
+date
短日期类型
+ datetime
长日期类型
+ clob
字符大对象
最多可以存储4G的字符串。
比如:存储一篇文章,存储一个说明。
超过255个字符的都要采用CLOB字符大对象来存储。
Character Large OBject:CLOB
+ blob
二进制大对象
Binary Large OBject
专门用来存储图片、声音、视频等流媒体数据。
往BLOB类型的字段上插入数据的时候,例如插入一个图片、视频等,
你需要使用IO流才行。
+ t_movie 电影表
专门存储电影信息的
- 删除表drop
drop 表名
如果表存在的话就会成功删除
如果不存在会报错
也可以这样删除
drop table if exits t_student
* insert插入数据
- 语法
insert into 表名(字段名1,字段名2,字段名3...) values(值1,值2,值3);
- 字段名和值要一一对应,数量要对应。数据类型要对应。
- insert语句但凡是执行成功了,那么必然会多一条记录。
- 没有给其它字段指定值的话,默认值是NULL。
- insert语句中的“字段名”可以省略(前面的字段名省略的话,等于都写上了!所以值也要都写上!)
- insert插入日期
-
数字格式化:format
select ename,sal from emp; -
格式化数字:format(数字, ‘格式’)
select ename,format(sal, ‘$999,999’) as sal from emp; -
str_to_date:将字符串varchar类型转换成date类型
insert into t_student(id,name,brith) values(1,'ZhangShang',str_to_date('01-10-1990','%d-%m-%Y'));
注意:如果提供的日期格式是 %Y-%m-%d 那么就不需要写str_to_date 会自动解析转化
-
date_format:将date类型转换成具有一定格式的varchar字符串类型。
-
注意:数据库中的有一条命名规范:
所有的标识符都是全部小写,单词和单词之间使用下划线进行衔接。
+ mysql中的日期格式
%Y 年
%m 月
%d 日
%h 时
% i 分
%s 秒
- now()获取系统当前时间
使用now()获取的时间带有时分秒信息,属于 datetime 类型
insert into t_student(id,name,brith) values(1,'ZhangShang',now());
* update改(DML语句)
语法:
updete 表名 set 字段名1 = 值1,字段名2 = 值2,字段名3 = 值3...where 条件;
注意,update需要条件限制,否则会将所有元素更新
# 更改部分数据
update t_user set name = 'jack',birth = '2000-10-11'
# 更改全部数据
update t_user set name = 'abc';
* 删除数据 delete(DML)
delete from 表名 where 条件;
注意:如果没有添加条件,会删除整张表的数据
* 快速建表
创建一个新表接收将某个或几个表的查询数据
create table emp2 as select * from emp;
注意,此方法还可以完成表的快速复制,可以复制表的结构和数据
也可以将某列等的结果作为一张表新建
* 快速删除表中的数据
- delete语句删除的特点
表中的数据被删除了,但是这个数据在硬盘上的真实存储空间不会被释放
缺点:删除效率低
优点:支持回滚(回滚是rollback),可以恢复数据
- truncate语句删除数据
特点:删除效率高,表被一次性截断,属于物理删除,不能恢复数据
缺点:不支持回滚,数据无法恢复
优点:删除效率高,速度快
作用:如果表中的数据量巨大,而要删除的数据的数据量巨大,如果使用delete删除数据可能要执行一个多小时,但是使用truncate只需要不到一秒
注意:drop table XXX 不是在删除数据,而是在删除表,是属于把表结构和数据一起删除了
* 约束
在创建表的时候可以给表的字段添加一些约束,保证这个表中的数据的完整性和有效性,作用就是保证表中数据有效
约束分为列级约束和表级约束,裂解约束就是直接在字段的后方加上约束,表级约束是如unique(name,sal)等,加在跟字段同级的地位
- 非空约束 not null
create table kkk(id int,name varchar(
255) not null);
如上,将not null加在字段的后方,该字段在insert时就不能传入null的数据
- 唯一性约束 unique
加在字段后方,保证该字段的数据都是唯一的,不重复的
注意:唯一性的数据不能重复,但是可以为null,null可以重复
+ 多字段联合唯一性(表级约束)
语法:
unique(字段1,字段2,...)
示例:
create table kkk(id int,name varchar(255),email varchar(255),unique(name,emial));
- 主键约束 primary key (PK)
主键特征:主键即为not null + unique
即为主键不能为null,也不能重复
create table ttt(id int primary key,name varchar(255));
也可以复合主键(不建议使用):
primary key(id,name);
+ 主键值建议的数据类型
建议使用:int,bright,char
不建议使用:varchar做主键,业务主键一般为数字,一般为定长
+ 主键其他的分类
- 自然主键:主键值是一个自然数,和业务无关
- 业务主键:主键值和业务紧密相关,如将银行卡账号作为主键值
- 实际开发中自然主键使用较多,主键一般只需要不重复即可,不需要有意义,业务主键不好,一旦业务发生变动,主键也需要变动,灵活性不好
+ 自增(auto_increment)
从1开始自增
自增可以用于维护主键值
create table ttt(id int primary key auto_increment,name varchar(255));
#能够让id进行自增,从1开始自增
- 外键约束 foreign key (FK)
外键字段为加上外键约束的字段,外键值为外键字段中的每一个值
由于如果要在一个表中描述多条信息,而且这些信息之间还有交叉,这样就会导致数据冗余,空间浪费
删除表的顺序?
先删子,再删父。
删除表的顺序?
先删子,再删父。
创建表的顺序?
先创建父,再创建子。
删除数据的顺序?
先删子,再删父。
插入数据的顺序?
先插入父,再插入子。
思考:子表中的外键引用的父表中的某个字段,被引用的这个字段必须是主键吗?
不一定是主键,但至少具有unique约束。
测试:外键可以为NULL吗?
外键值可以为NULL。
- 检查约束 check (mysql不支持)
check在mysql中是不支持的,但是在oracle中是支持的
* 存储引擎
- 存储引擎是MySQL中特有的一个术语,其它数据库中没有。(Oracle中有,但是不叫这个名字)
- 实际上存储引擎是一个表存储/组织数据的方式。
- 不同的存储引擎,表存储数据的方式不同。
- 给表添加/指定引擎
-
在建表的时候可以在最后小括号的")"的右边使用:
ENGINE来指定存储引擎。
CHARSET来指定这张表的字符编码方式。 -
结论:
mysql默认的存储引擎是:InnoDB mysql默认的字符编码方式是:utf8
# 建表时指定存储引擎,以及字符编码方式。
create table t_product(
id int primary key,
name varchar(255)
)engine=InnoDB default charset=gbk;
- 引擎类型
mysql支持九大存储引擎,当前5.5.36支持8个。版本不同支持情况不同。
查看mysql的所有引擎:show engines \Gwwwww
*************************** 1. row ***************************
Engine: FEDERATED
Support: NO
Comment: Federated MySQL storage engine
Transactions: NULL
XA: NULL
Savepoints: NULL
*************************** 2. row ***************************
Engine: MRG_MYISAM
Support: YES
Comment: Collection of identical MyISAM tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 3. row ***************************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
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: CSV
Support: YES
Comment: CSV storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 6. row ***************************
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
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: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
*************************** 9. row ***************************
Engine: PERFORMANCE_SCHEMA
Support: YES
Comment: Performance Schema
Transactions: NO
XA: NO
Savepoints: NO
- mysql常用的存储引擎
+ MyISAM存储引擎
使用三个文件表示每个表:
格式文件 — 存储表结构的定义(mytable.frm)
数据文件 — 存储表行的内容(mytable.MYD)
索引文件 — 存储表上索引(mytable.MYI):索引是一本书的目录,缩小扫描范围,提高查询效率的一种机制。
可被转换为压缩、只读表来节省空间
MyISAM不支持事务机制,安全性低。
对于一张表来说,只要是主键,
或者加有unique约束的字段上会自动创建索引。
MyISAM存储引擎特点:
可被转换为压缩、只读表来节省空间
这是这种存储引擎的优势!!!!
MyISAM不支持事务机制,安全性低。
+ InnoDB存储引擎
这是mysql默认的存储引擎,同时也是一个重量级的存储引擎。
InnoDB支持事务,支持数据库崩溃后自动恢复机制。
InnoDB存储引擎最主要的特点是:非常安全。
– 每个 InnoDB 表在数据库目录中以.frm 格式文件表示
– InnoDB 表空间 tablespace 被用于存储表的内容(表空间是一个逻辑名称。表空间存储数据+索引。)
– 提供一组用来记录事务性活动的日志文件
– 用 COMMIT(提交)、SAVEPOINT 及ROLLBACK(回滚)支持事务处理
– 提供全 ACID 兼容
– 在 MySQL 服务器崩溃后提供自动恢复
– 多版本(MVCC)和行级锁定
– 支持外键及引用的完整性,包括级联删除和更新
InnoDB最大的特点就是支持事务(事物就是为了解决数据安全问题):
以保证数据的安全。效率不是很高,并且也不能压缩,不能转换为只读,
不能很好的节省存储空间。
+ MEMORY存储引擎(内存存储引擎)
使用 MEMORY 存储引擎的表,其数据存储在内存中,且行的长度固定,
这两个特点使得 MEMORY 存储引擎非常快。
查询速度快,效率是最高的
一断电数据就消失,不安全
内存上取数据快是因为内存上取数据是取决于电的速度,即为光速,而内存上取数据则为机械行为
– 在数据库目录内,每个表均以.frm 格式的文件表示。
– 表数据及索引被存储在内存中。(目的就是快,查询快!)
– 表级锁机制。
– 不能包含 TEXT 或 BLOB 字段。
MEMORY 存储引擎以前被称为HEAP 引擎。
MEMORY引擎优点:查询效率是最高的。不需要和硬盘交互。
MEMORY引擎缺点:不安全,关机之后数据消失。因为数据和索引都是在内存当中。
* 事务(DML独有)
-
事务(transaction)就是一个完整的业务逻辑
-
业务逻辑就是一个业务完整的执行流程,该操作是一个最小的工作单元,要么同时成功,要么同时失败,不可再分,否则可能造成数据不同步
-
只有DML语句才有事务,因为只有数据的增删改才需要事务进行数据同步变化
-
说到底,一个事务就是多条DML语句同时成功或同时失败
- 事务执行流程
- 事务执行过程中,每一条DML语句的操作都会记录到事务性活动的日志文件中
- 在事务执行过程中我们可以提交事务,也可以回滚事务
- 提交事务:
- 清空事务性活动的日志文件,将数据全部彻底持久化到数据库中
- 提交事务标志着事务的结束,并且是一种全部成功的结束
- 回滚事务:
- 将之前的所以DML语句全部撤销,并且清空事务性活动的日志文件
- 回滚事务标志着事务的结束,并且是全部失败的结束
- 提交事务:
- 如何提交事务于回滚事务
- 提交事务 : commit
- 回滚事务 : rollback语句
注意:mysql在默认情况下是自动提交事务的,即为每执行一条DML语句就提交一次,所以不采用事务的情况下就无法进行回滚
如果要制止mysql每执行一次就自动提交数据的行为,就需要使用事务
#第一步开启事务
start transaction;
#第二步可以执行所需要的DML语句,即为对数据库进行增删改
.........
#第三步需要进行事务提交,即为等待上方的多条DML语句执行成功后将数据存入数据库
commit;
- 事务的四个特性
-
A : 原子性
事务是最小的工作单元,不可再分
-
C : 一致性
对于所有的事务要求再同一个事务中所有的操作必须同时成功,或者同时失败,以保证数据的一致性
-
I : 隔离性
事务之间是相互隔离不互相影响的
-
D : 持久性
事务最终结束的一个保障,事务提交就相当于将没有保存到硬盘上的数据保存到硬盘上
- 事务的四个隔离级别
事务之间的隔离级别有四个:
-
读未提交(read uncommited)(最低的隔离级别)(没提交就读到了)
即为事务A可以读取到事务B未提交的数据
存在的问题:脏读现象(dirty read)
这种隔离级别一般是理论上的,大多数数据库隔离级别都在二档以上
-
读已提交(read commited)(提交之后才能读到)
事务A只能读取到事务B提交之后的数据
解决了脏读现象
存在的问题:不可重复读取数据
不可重复读取数据:即为在事务开启之后进行多次查询可能导致数据查询条数对不上的情况
这种隔离级别是比较真实的数据,每次读取到的数据都是绝对的真实
属于oracle默认的隔离级别
-
可重复读(repeatable read)(提交之后也读不到)
提交之后也读取不到,永远是刚开启事务时的数据
可重复读取:即为在事务开启之后不管是多久,每一次在事务中读取到的数据都是一致的,即使此时有其他事务将数据库进行修改了,并且提交了,原先事务读取到的数据还是不会改变
解决了不可重复读
存在的问题:会出现幻读的情况
可重复读是mysql中默认的事务隔离级别
-
序列化/串行化(serializable)
这是最高的隔离级别,解决了所有问题,这个隔离级别表示事务排队,不能并发
类似于synchronized,属于一种事务同步操作,每一次读取到的数据都是真实的,而且是效率最底下的。
- 设置隔离级别
以下是设置全局隔离级别为xxxxxx
set global transaction isolation level read xxxxxx;
- 查看隔离级别
select @@tx_isolation
- 事务的四个隔离级别示例
-
read uncommited
-
read commited
-
repeatable read
-
serializable
* 索引(index)
- 索引添加在数据库的表上,为了提高查询效率存在的机制
- 一张表可以添加一个索引,多字段也可以联合添加索引,索引相当于一本书的目录,为了缩小扫描范围而存在的机制
在查询数据时,如果没有为所要查询的数据添加索引,就会导致mysql进行全表扫描,效率比较低
- mysql扫描方式
方式1:全表扫描
方式2:根据索引扫描
- 在mysql中索引是需要排序的,并且这个索引的排序和TreeSet数据结构相同,TreeSet(TreeMap)底层是一个自平衡的二叉树
- 索引在mysql中是一个B-Tree数据结构
- 遵循左小右大原则存放。采用中序遍历方式遍历取数据。
- 索引实现原理
- 在任何数据库当中主键上都会自动添加索引对象,id字段上自动有索引,因为id是PK。另外在mysql当中,一个字段上如果有unique约束的话,也会自动创建索引对象
- 在任何数据库当中,任何一张表的任何一条记录在硬盘存储上都有一个硬盘的物理存储编号。
- 在mysql当中,索引是一个单独的对象,不同的存储引擎以不同的形式存在,在MyISAM存储引擎中,索引存储在一个.MYI文件中。在InnoDB存储引擎中索引存储在一个逻辑名称叫做tablespace的当中。在MEMORY存储引擎当中索引被存储在内存当中。不管索引存储在哪里,索引在mysql当中都是一个树的形式存在。(自平衡二叉树:B-Tree)
- 索引怎么创建与删除
创建索引:
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索引对象删除。
- 查看sql语句是否使用索引进行检索
mysql> explain select * from emp where ename = 'KING';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
扫描14条记录:说明没有使用索引。type=ALL
mysql> create index emp_ename_index on emp(ename);
mysql> explain select * from emp where ename = 'KING';
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
| 1 | SIMPLE | emp | ref | emp_ename_index | emp_ename_index | 33 | const | 1 | Using where |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
- 索引失效条件
+ 情况1
ename上即使添加了索引,也不会走索引,为什么?
原因是因为模糊匹配当中以“%”开头了!
尽量避免模糊查询的时候以“%”开始。
这是一种优化的手段/策略。
explain select * from emp where ename like '%T';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
+ 情况2
使用or的时候会失效,如果使用or那么要求or两边的条件字段都要有
索引,才会走索引,如果其中一边有一个字段没有索引,那么另一个
字段上的索引也会实现。所以这就是为什么不建议使用or的原因。
explain select * from emp where ename = 'KING' or job = 'MANAGER';
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | emp_ename_index | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
+ 情况3
使用复合索引的时候,没有使用左侧的列查找,索引失效
什么是复合索引?
两个字段,或者更多的字段联合起来添加一个索引,叫做复合索引。
explain select * from emp where job = 'MANAGER';
+----+-------------+-------+------+-------------------+-------------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-------------------+-------------------+---------+-------+------+-------------+
| 1 | SIMPLE | emp | ref | emp_job_sal_index | emp_job_sal_index | 30 | const | 3 | Using where |
+----+-------------+-------+------+-------------------+-------------------+---------+-------+------+-------------+
explain select * from emp where sal = 800;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
+ 情况4
在where当中索引列参加了运算,索引失效。
explain select * from emp where sal = 800;
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
| 1 | SIMPLE | emp | ref | emp_sal_index | emp_sal_index | 9 | const | 1 | Using where |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
mysql> explain select * from emp where sal+1 = 800;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
+ 情况5
在where当中索引列使用了函数
explain select * from emp where lower(ename) = 'smith';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
- 索引的分类
-
单一索引
具有unique约束的字段上添加索引。
-
复合索引
两个字段或者更多的字段上添加索引。
主键索引:主键上添加索引。
唯一性索引:具有unique约束的字段上添加索引。
* 视图(view)
view:站在不同的角度去看待同一份数据。
- 创建与删除视图
创建视图对象:
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> select * from dept2;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
| 60 | SALES | BEIJING |
+--------+------------+----------+
// 面向视图删除
mysql> delete from dept2_view;
// 查询原表数据
mysql> select * from dept2;
Empty set (0.00 sec)
// 创建视图对象
create view
emp_dept_view
as
select
e.ename,e.sal,d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno;
// 查询视图对象
mysql> select * from emp_dept_view;
// 面向视图更新
update emp_dept_view set sal = 1000 where dname = 'ACCOUNTING';
### - 作用介绍
-
假设有一条非常复杂的SQL语句,而这条SQL语句需要在不同的位置上反复使用。
每一次使用这个sql语句的时候都需要重新编写,很长,很麻烦,怎么办?
可以把这条复杂的SQL语句以视图对象的形式新建。
在需要编写这条SQL语句的位置直接使用视图对象,可以大大简化开发。
并且利于后期的维护,因为修改的时候也只需要修改一个位置就行,只需要
修改视图对象所映射的SQL语句。 -
我们以后面向视图开发的时候,使用视图的时候可以像使用table一样。
可以对视图进行增删改查等操作。视图不是在内存当中,视图对象也是
存储在硬盘上的,不会消失。 -
再提醒一下:
视图对应的语句只能是DQL语句。
但是视图对象创建完成之后,可以对视图进行增删改查等操作。
* DBA常用命令
-
重点掌握:
数据的导入和导出(数据的备份)
其它命令了解一下即可。 -
数据导出与导入
数据导出? 注意:在windows的dos命令窗口中: mysqldump bjpowernode>D:\bjpowernode.sql -uroot -p123456 可以导出指定的表吗? mysqldump bjpowernode emp>D:\bjpowernode.sql -uroot -p123456 数据导入? 注意:需要先登录到mysql数据库服务器上。 然后创建数据库:create database bjpowernode; 使用数据库:use bjpowernode 然后初始化数据库:source D:\bjpowernode.sql
* 数据范式
设计数据库表的时候,按照以下的范式进行,可以避免表中数据的冗余,空间的浪费。
- 第一范式
要求任何一张表必须有主键,每一个字段原子性不可再分。
最核心,最重要的范式,所有表的设计都需要满足。
必须有主键,并且每一个字段都是原子性不可再分。
- 第二范式
建立在第一范式的基础之上,要求所有非主键字段完全依赖主键,
不要产生部分依赖。
建立在第一范式的基础之上,
要求所有非主键字段必须完全依赖主键,不要产生部分依赖。
- 第三范式
建立在第二范式的基础之上,要求所有非主键字段直接依赖主键,
不要产生传递依赖。
第三范式建立在第二范式的基础之上
要求所有非主键字典必须直接依赖主键,不要产生传递依赖。
* 表设计的总结
一对多:
一对多,两张表,多的表加外键!!!!!!!!!!!!
多对多:
多对多,三张表,关系表两个外键!!!!!!!!!!!!!!!
一对一:
一对一放到一张表中不就行了吗?为啥还要拆分表?
在实际的开发中,可能存在一张表字段太多,太庞大。这个时候要拆分表。
一对一怎么设计?
没有拆分表之前:一张表
t_user
id login_name login_pwd real_name email address........
---------------------------------------------------------------------------
1 zhangsan 123 张三 zhangsan@xxx
2 lisi 123 李四 lisi@xxx
...
这种庞大的表建议拆分为两张:
t_login 登录信息表
id(pk) login_name login_pwd
---------------------------------
1 zhangsan 123
2 lisi 123
t_user 用户详细信息表
id(pk) real_name email address........ login_id(fk+unique)
-----------------------------------------------------------------------------------------
100 张三 zhangsan@xxx 1
200 李四 lisi@xxx 2
口诀:一对一,外键唯一!!!!!!!!!!
注意:在windows的dos命令窗口中:
mysqldump bjpowernode>D:\bjpowernode.sql -uroot -p123456
可以导出指定的表吗?
mysqldump bjpowernode emp>D:\bjpowernode.sql -uroot -p123456
数据导入?
注意:需要先登录到mysql数据库服务器上。
然后创建数据库:create database bjpowernode;
使用数据库:use bjpowernode
然后初始化数据库:source D:\bjpowernode.sql
## * 数据范式
设计数据库表的时候,按照以下的范式进行,可以避免表中数据的冗余,空间的浪费。
### - 第一范式
**要求任何一张表必须有主键,每一个字段原子性不可再分。**
最核心,最重要的范式,所有表的设计都需要满足。
必须有主键,并且每一个字段都是原子性不可再分。
### - 第二范式
**建立在第一范式的基础之上,要求所有非主键字段完全依赖主键,**
**不要产生部分依赖。**
建立在第一范式的基础之上,
要求所有非主键字段必须完全依赖主键,不要产生部分依赖。
### - 第三范式
**建立在第二范式的基础之上,要求所有非主键字段直接依赖主键,**
**不要产生传递依赖。**
第三范式建立在第二范式的基础之上
要求所有非主键字典必须直接依赖主键,不要产生传递依赖。
## * 表设计的总结
```mysql
一对多:
一对多,两张表,多的表加外键!!!!!!!!!!!!
多对多:
多对多,三张表,关系表两个外键!!!!!!!!!!!!!!!
一对一:
一对一放到一张表中不就行了吗?为啥还要拆分表?
在实际的开发中,可能存在一张表字段太多,太庞大。这个时候要拆分表。
一对一怎么设计?
没有拆分表之前:一张表
t_user
id login_name login_pwd real_name email address........
---------------------------------------------------------------------------
1 zhangsan 123 张三 zhangsan@xxx
2 lisi 123 李四 lisi@xxx
...
这种庞大的表建议拆分为两张:
t_login 登录信息表
id(pk) login_name login_pwd
---------------------------------
1 zhangsan 123
2 lisi 123
t_user 用户详细信息表
id(pk) real_name email address........ login_id(fk+unique)
-----------------------------------------------------------------------------------------
100 张三 zhangsan@xxx 1
200 李四 lisi@xxx 2
口诀:一对一,外键唯一!!!!!!!!!!
数据库设计三范式是理论上的。
实践和理论有的时候有偏差。
最终的目的都是为了满足客户的需求,有的时候会拿冗余换执行速度。
因为在sql当中,表和表之间连接次数越多,效率越低。(笛卡尔积)
有的时候可能会存在冗余,但是为了减少表的连接次数,这样做也是合理的,
并且对于开发人员来说,sql语句的编写难度也会降低。