很久没用了,今天把知识系统的梳理一遍
文章目录
一.数据库概念
1. 数据库的英文单词: DataBase 简称 : DB
2. 什么数据库?
用于存储和管理数据的仓库。
3. 数据库的特点:
①. 持久化存储数据的。其实数据库就是一个文件系统
②. 方便存储和管理数据
③. 使用了统一的方式操作数据库 – SQL
4.常见的数据库及简介:
MySQL:开源免费的数据库,小型的数据库,已经被 Oracle 收购了。MySQL6.x 版本也开始收费。后来 Sun 公司收购了 MySQL,而 Sun 公司又被 Oracle 收购
Oracle:收费的大型数据库,Oracle 公司的产品。
DB2 :IBM 公司的数据库产品,收费的。常应用在银行系统中
SQL Server:MicroSoft 公司收费的中型的数据库。C#、.net 等语言常使用。
SQLite: 嵌入式的小型数据库,应用在手机端,如:Android
二.Mysql安装与使用
1.MySQL安装
安装教程
2.卸载Mysql
卸载教程
3.Mysql的启动与关闭
①手动启动:win+R,输入services.msc,找到Mysql并启动或关闭
②终端启动与关闭
4.登入与退出
①mysql -uroot -p密码 或直接输入 mysql -uroot -proot
这种方式为本地登入
②mysql -hip -uroot -p连接目标的密码 或直接输入 mysql -hip -uroot -proot
这种方式为远程登入
但是该方式需要开启可以使用远程才可以用
其它开启远程连接权限
③mysql --host=ip --user=root --password=连接目标的密码
④MySQL退出
1. exit
2. quit
三.SQL基本概念与注释及分类
sql:
Structured Query Language:结构化查询语言
其实就是定义了操作所有关系型数据库的规则。每一种数据库操作的方式存在不一样的地方,称为“方言”。
注释:
3 种注释
* 单行注释: - - 注释内容 或 # 注释内容(mysql 特有)
* 多行注释: /* 注释 */
分类
1.DDL(Data Definition Language)数据定义语言
用来定义数据库对象:数据库,表等。关键字:create, drop,alter 等
2. DML(Data Manipulation Language)数据操作语言
用来对数据库中表的数据进行增删改。关键字:insert, delete, update 等
3. DQL(Data Query Language)数据查询语言
用来查询数据库中表的记录(数据)。关键字:select, where 等
4. DCL(Data Control Language)数据控制语言(了解)
用来定义数据库的访问权限和安全级别,及创建用户。关键字:GRANT, REVOKE 等
总结:操作库:DDL
操作表:DDL,DQL,DML
权限:DCL
四. 数据库、表的CRUD操作
1.DDL(Data Definition Language)
前面已经说了操作数据库的只有DDL(DCL不考虑),同时还可以操作表
①操作库:
1. C(Create):创建
创建数据库:
create database 数据库名称;
创建数据库,判断不存在,再创建:
create database if not exists 数据库名称;
创建数据库,并指定字符集
create database 数据库名称 character set 字符集名;
2. R(Retrieve):查询
查询所有数据库的名称:
show databases;
查询某个数据库的字符集:查询某个数据库的创建语句
show create database 数据库名称;
3. U(Update):修改
修改数据库的字符集
alter database 数据库名称 character set 字符集名称;
4. D(Delete):删除
删除数据库
drop database 数据库名称;
判断数据库存在,存在再删除
drop database if exists 数据库名称;
5. 使用数据库
查询当前正在使用的数据库名称
select database();
使用数据库
use 数据库名称;
下面依次演示:
创建:
查询:
修改:
删除:
使用:
②操作表
1. C(Create):创建
1. 语法:
create table 表名(
列名1 数据类型1,
列名2 数据类型2,
....
列名n 数据类型n
);
* 注意:最后一列,不需要加逗号(,)
* 数据库类型:
1. int:整数类型
* age int,
2. double:小数类型
* score double(5,2) 表示最多有5位,其中小数点后保留2位那么他的最大值为999.99
3. date:日期,只包含年月日,yyyy-MM-dd
4. datetime:日期,包含年月日时分秒 yyyy-MM-dd HH:mm:ss
5. timestamp:时间错类型 包含年月日时分秒 yyyy-MM-dd HH:mm:ss
* 如果将来不给这个字段赋值,或赋值为null,则默认使用当前的系统时间,来自动赋值
6. varchar:字符串
* name varchar(20):姓名最大20个字符
* zhangsan 8个字符 张三 2个字符
* 创建表
create table student1(
id int,
name varchar(32),
age int ,
score double(4,1),
birthday date,
insert_time timestamp
);
* 复制表:
* create table 表名 like 被复制的表名;
2. R(Retrieve):查询
* 查询某个数据库中所有的表名称
* show tables;
* 查询表结构
* desc 表名;
3. U(Update):修改
1. 修改表名
alter table 表名 rename to 新的表名;
2. 修改表的字符集
alter table 表名 character set 字符集名称;
3. 添加一列
alter table 表名 add 列名 数据类型;
4. 修改列名称 类型
alter table 表名 change 列名 新列名 新数据类型;
alter table 表名 modify 列名 新数据类型;
5. 删除列
alter table 表名 drop 列名;
4. D(Delete):删除
* drop table 表名;
* drop table if exists 表名 ;
演示:
创建
复制
查询:
表名:
表结构:
修改:
表名
字符集
补充,修改字段的字符集:
alter table 表名 modify 列名 数据类型 character set 字符集(这个不演示了)
加列
该列名与类型:
删除列
删除表
2.DML(Data Manipulation Language)
下面的演示使用Sqlyog这个软件
1. 添加数据:
* 语法:
* insert into 表名(列名1,列名2,...列名n) values(值1,值2,...值n);
* 注意:
1. 列名和值要一一对应。
2. 如果表名后,不定义列名,则默认给所有列添加值
insert into 表名 values(值1,值2,...值n);
3. 除了数字类型,其他类型需要使用引号(单双都可以)引起来
2. 删除数据:
* 语法:
* delete from 表名 [where 条件]
* 注意:
1. 如果不加条件,则删除表中所有记录。
2. 如果要删除所有记录
1. delete from 表名; -- 不推荐使用。有多少条记录就会执行多少次删除操作
2. TRUNCATE TABLE 表名; -- 推荐使用,效率更高 先删除表,然后再创建一张一样的表。
3. 修改数据:
* 语法:
* update 表名 set 列名1 = 值1, 列名2 = 值2,... [where 条件];
* 注意:如果不加任何条件,则会将表中所有记录全部修改。
演示:
插入:
INSERT INTO student_copy (id,NAME) VALUES(1,“张三”),(2,“李四”);
删除
DELETE FROM student_copy;
TRUNCATE TABLE STUDENT_COPY
修改
INSERT INTO student_copy (id,NAME) VALUES(1,“张三”),(2,“李四”);
update student_copy set name="王五"
上面的所有name都改为了王五
3.DCL(Data Control Language)【DBA来做】
1. 管理用户
1. 添加用户:
* 语法:CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
可能会碰到the skip-grant-tables is running而无法用,需要先用
flush privileges;来清理权限
2. 删除用户:
* 语法:DROP USER '用户名'@'主机名';
3. 修改用户密码:
UPDATE USER SET PASSWORD = PASSWORD('新密码') WHERE USER = '用户名';
UPDATE USER SET PASSWORD = PASSWORD('abc') WHERE USER = 'lisi';
SET PASSWORD FOR '用户名'@'主机名' = PASSWORD('新密码');
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('123');
* mysql中忘记了root用户的密码?
1. cmd -- > net stop mysql 停止mysql服务
* 需要管理员运行该cmd
2. 使用无验证方式启动mysql服务: mysqld --skip-grant-tables
3. 打开新的cmd窗口,直接输入mysql命令,敲回车。就可以登录成功
4. use mysql;
5. update user set password = password('你的新密码') where user = 'root';
6. 关闭两个窗口
7. 打开任务管理器,手动结束mysqld.exe 的进程
8. 启动mysql服务
9. 使用新密码登录。
4. 查询用户:
-- 1. 切换到mysql数据库
USE myql;
-- 2. 查询user表
SELECT * FROM USER;
* 通配符: % 表示可以在任意主机使用用户登录数据库
2. 权限管理:
1. 查询权限:
-- 查询权限
SHOW GRANTS FOR '用户名'@'主机名';
SHOW GRANTS FOR 'lisi'@'%';
2. 授予权限:
-- 授予权限
grant 权限列表 on 数据库名.表名 to '用户名'@'主机名';
-- 给张三用户授予所有权限,在任意数据库任意表上
GRANT ALL ON *.* TO 'zhangsan'@'localhost';
3. 撤销权限:
-- 撤销权限:
revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名';
REVOKE UPDATE ON db3.`account` FROM 'lisi'@'%';
非重点不做演示
4.DQL(Data Query Language)
该部分是重点也是难点
* select * from 表名;
1. 语法:
select
字段列表
from
表名列表
where
条件列表
group by
分组字段
having
分组之后的条件
order by
排序
limit
分页限定
2. 基础查询
1. 多个字段的查询
select 字段名1,字段名2... from 表名;
* 注意:
* 如果查询所有字段,则可以使用*来替代字段列表。
2. 去除重复:
* distinct
3. 计算列
* 一般可以使用四则运算计算一些列的值。(一般只会进行数值型的计算)
* ifnull(表达式1,表达式2):null参与的运算,计算结果都为null
* 表达式1:哪个字段需要判断是否为null
* 如果该字段为null后的替换值。
4. 起别名:
* as:as也可以省略
3. 条件查询
1. where子句后跟条件
2. 运算符
* > 、< 、<= 、>= 、= 、<> '<>'表示不等于
* BETWEEN...AND
* IN( 集合)
* LIKE:模糊查询
* 占位符:
* _:单个任意字符
* %:多个任意字符
* IS NULL
* and 或 &&
* or 或 ||
* not 或 !
-- 查询年龄大于20岁
这些语句仅供参考
SELECT * FROM student WHERE age > 20;
SELECT * FROM student WHERE age >= 20;
-- 查询年龄等于20岁
SELECT * FROM student WHERE age = 20;
-- 查询年龄不等于20岁
SELECT * FROM student WHERE age != 20;
SELECT * FROM student WHERE age <> 20;
-- 查询年龄大于等于20 小于等于30
SELECT * FROM student WHERE age >= 20 && age <=30;
SELECT * FROM student WHERE age >= 20 AND age <=30;
SELECT * FROM student WHERE age BETWEEN 20 AND 30;
-- 查询年龄22岁,18岁,25岁的信息
SELECT * FROM student WHERE age = 22 OR age = 18 OR age = 25
SELECT * FROM student WHERE age IN (22,18,25);
-- 查询英语成绩为null
SELECT * FROM student WHERE english = NULL; -- 不对的。null值不能使用 = (!=) 判断
SELECT * FROM student WHERE english IS NULL;
-- 查询英语成绩不为null
SELECT * FROM student WHERE english IS NOT NULL;
-- 查询姓马的有哪些? like
SELECT * FROM student WHERE NAME LIKE '马%';
-- 查询姓名第二个字是化的人
SELECT * FROM student WHERE NAME LIKE "_化%";
-- 查询姓名是3个字的人
SELECT * FROM student WHERE NAME LIKE '___';
-- 查询姓名中包含德的人
SELECT * FROM student WHERE NAME LIKE '%德%';
演示:
我们下面的查询以此表为基础
基础查询
1. 多个字段的查询
SELECT id,NAME,age FROM student_copy;
2. 去除重复
SELECT DISTINCT age,NAME FROM student_copy;
注意这里认为的重复指的是记录要完全一样而不是只要某个字段一样
SELECT DISTINCT age FROM student_copy;
3.计算列
SELECT NAME,age+age FROM student_copy;
注意:如果参与运算的有NULL运算结果也为NULL
下面为了演示将表改为下面:(99–>NULL),之后的演示不做说明也用这个
SELECT NAME,age+score FROM student_copy;
使用IFNULL来消除
SELECT NAME,age+IFNULL(score,0) FROM student_copy;
4.起别名:
SELECT NAME,age+IFNULL(score,0) (as) scores FROM student_copy;(as可要可不要)
条件查询
不等于和等于的演示
SELECT NAME,age FROM student_copy WHERE age<>22
SELECT NAME,age FROM student_copy WHERE age=22
BETWEEN…AND
SELECT NAME,age FROM student_copy WHERE age BETWEEN 20 AND 28
IN( 集合)
SELECT NAME,age FROM student_copy WHERE age IN (23,27,31)
LIKE:模糊查询
_:单个任意字符
%:多个任意字符
SELECT NAME,age FROM student_copy WHERE NAME LIKE "赵 _"
SELECT NAME,age FROM student_copy WHERE NAME LIKE "李%"
IS NULL
SELECT NAME,age,score FROM student_copy WHERE score IS NULL
注意不可以写score = NULL 因为NULL和任何都不相等,包括他自己
and 或 && (&&不是常用的)
SELECT NAME,age,score FROM student_copy WHERE NAME=“赵六” AND age=27
or 或 || (||不是常用的)
SELECT NAME,age,score FROM student_copy WHERE NAME=“赵六” OR age=22
not 或 !
SELECT NAME,age,score FROM student_copy WHERE NOT NAME="赵六"
下面继续介绍其他的DQL语句:
1. 排序查询
* 语法:order by 子句
* order by 排序字段1 排序方式1 , 排序字段2 排序方式2...
* 排序方式:
* ASC:升序,默认的。
* DESC:降序。
* 注意:
* 如果有多个排序条件,则当前边的条件值一样时,才会判断第二条件。
2. 聚合函数:将一列数据作为一个整体,进行纵向的计算。
1. count:计算个数
1. 一般选择非空的列:主键
2. count(*)
2. max:计算最大值
3. min:计算最小值
4. sum:计算和
5. avg:计算平均值
* 注意:聚合函数的计算,排除null值。
解决方案:
1. 选择不包含非空的列进行计算
2. IFNULL函数
3. 分组查询:
1. 语法:group by 分组字段;
2. 注意:
1. 分组之后查询的字段:分组字段、聚合函数
2. where 和 having 的区别?
1. where 在分组之前进行限定,如果不满足条件,则不参与分组。having在分组之后进行限定,如果不满足结果,则不会被查询出来
2. where 后不可以跟聚合函数,having可以进行聚合函数的判断。
(下面语句供参考)
-- 按照性别分组。分别查询男、女同学的平均分
SELECT sex , AVG(math) FROM student GROUP BY sex;
-- 按照性别分组。分别查询男、女同学的平均分,人数
SELECT sex , AVG(math),COUNT(id) FROM student GROUP BY sex;
-- 按照性别分组。分别查询男、女同学的平均分,人数 要求:分数低于70分的人,不参与分组
SELECT sex , AVG(math),COUNT(id) FROM student WHERE math > 70 GROUP BY sex;
-- 按照性别分组。分别查询男、女同学的平均分,人数 要求:分数低于70分的人,不参与分组,分组之后。人数要大于2个人
SELECT sex , AVG(math),COUNT(id) FROM student WHERE math > 70 GROUP BY sex HAVING COUNT(id) > 2;
SELECT sex , AVG(math),COUNT(id) 人数 FROM student WHERE math > 70 GROUP BY sex HAVING 人数 > 2;
4. 分页查询
1. 语法:limit 开始的索引,每页查询的条数;
2. 公式:开始的索引 = (当前的页码 - 1) * 每页显示的条数
-- 每页显示3条记录
SELECT * FROM student LIMIT 0,3; -- 第1页
SELECT * FROM student LIMIT 3,3; -- 第2页
SELECT * FROM student LIMIT 6,3; -- 第3页
3. limit 是一个MySQL"方言"
演示:下面以此表为例
排序查询
SELECT NAME,age FROM student_copy ORDER BY age ASC
注意默认是升序,即ASC可以不写
SELECT NAME,age FROM student_copy ORDER BY age DESC
如果有多个排序条件,则当前边的条件值一样时,才会判断第二条件。看下面这个例子:
SELECT NAME,age,score FROM student_copy ORDER BY age DESC,score DESC
由于两个22一样,这个时候就看第二个字段即score
聚合函数
下面为讲解方便使用该表
count:计算个数(一般单独为一个字段使用)
SELECT COUNT(age) FROM student_copy
SELECT COUNT(score) FROM student_copy
这里不为4而为3,是因为聚合函数的计算,排除null值。
下面处理一下
SELECT COUNT(IFNULL(score,0)) AS num FROM student_copy
max:计算最大值
SELECT MAX(score) FROM student_copy
这里的NULL被忽略了
min:计算最小值
略
sum:计算和
SELECT SUM(score) FROM student_copy
这里的NULL被忽略了
avg:计算平均值
SELECT AVG(score) FROM student_copy
注意:聚合函数的计算,排除null值。
选择不包含非空的列进行计算
IFNULL函数
分组查询
下面用这个表
对与聚合函数与分组查询来说,当使用后,如果还有其它的字段一起查,那么查到的
记录条数以聚合函数与分组查询对应字段的记录条数为准(小知识,了解即可)
举个例子:
SELECT MAX(id),NAME FROM student_copy GROUP BY sex
正儿八经的分组查询:
SELECT sex,MAX(score) FROM student_copy GROUP BY sex
结果为男女最高分,果然巾帼不让须眉呀
这里还有一个比较重要的知识点(要格外注意,面试经常问):
①where 在分组之前进行限定(这句话有两个意思,where语句写在group by前
,同时也是先利用where筛选再去分组,后面having一样),如果不满足条件,
则不参与分组。having在分组之后进行限定如果不满足结果,则不会被查询出来
②where 后不可以跟聚合函数,having可以进行聚合函数的判断。
下面这句话表示先排除age>22的记录,在分组,此时为第3,4条记录,两条记录一个一组,接着每个组id都为1故两者都选中
SELECT sex,MAX(score) FROM student_copy WHERE age>22 GROUP BY sex HAVING COUNT(id)=1
最后要说明一下group by 与order by的顺序问题,group by要在order by的前面,且不会在分组内部进行排序
分页查询(Mysql特有的)
公式:开始的索引 = (当前的页码 - 1) * 每页显示的条数
SELECT * FROM student_copy LIMIT 2,1; (第3页,每页一条记录)
五.表的约束
* 概念: 对表中的数据进行限定,保证数据的正确性、有效性和完整性。
* 分类四大约束:
1. 主键约束:primary key(重要)
2. 非空约束:not null(基础)
3. 唯一约束:unique(基础)
4. 外键约束:foreign key(重要,难点)
下面四个约束将以创建表时添加,创建表后的添加,创建表后的删除来讲解,
非空约束
创建表时添加约束
CREATE TABLE company(
id INT,
NAME VARCHAR(10) NOT NULL
);
创建表完后,添加非空约束
添加前:
ALTER TABLE student_copy MODIFY age INT NOT NULL
添加后:
删除name的非空约束
ALTER TABLE student_copy MODIFY age INT 不加NOT NULL表示把非空这一选项还原为默认
唯一约束
这一部分可以直接把代码拷贝自行演示
注意mysql中,可以允许多个null,这不违背唯一性
创建表时添加约束
CREATE TABLE company(
id INT UNIQUE,
NAME VARCHAR(10)
);
创建表后添加约束
ALTER TABLE company DROP INDEX id
创建表后删除约束
ALTER TABLE company MODIFY id INT UNIQUE
主键约束(重点)
含义:非空且唯一
一张表只能有一个字段为主键
主键就是表中记录的唯一标识
创建表时添加约束
CREATE TABLE company(
id INT PRIMARY KEY,
NAME VARCHAR(10)
);
创建表后删除约束
ALTER TABLE company DROP PRIMARY KEY
创建表后添加约束
ALTER TABLE company MODIFY id INT PRIMARY KEY
补充:自动增长
其增删改与非空约束一样,这里简单介绍一下
自动增长:
1. 概念:如果某一列是数值类型的,使用 auto_increment 可以来完成值得自动增长
2. 在创建表时,添加主键约束,并且完成主键自增长
create table stu(
id int primary key auto_increment,-- 给id添加主键约束
name varchar(20)
);
3. 删除自动增长
ALTER TABLE stu MODIFY id INT;
4. 添加自动增长
ALTER TABLE stu MODIFY id INT AUTO_INCREMENT;
外键约束(重点,难点)
先准备两张表
employee表
department表
创建表时添加约束
现在department表存在,employee不存在(外键对应的表是主表)
CREATE TABLE employee(
id INT PRIMARY KEY,
NAME VARCHAR(10),
uid INT,
CONSTRAINT emp_dep_id FOREIGN KEY (uid) REFERENCES department(uid)
);
当然在创建外键时可以省略constraint 外键名,那么这时系统会自动给你分配外键
上面的emp_dep_id其实不一定叫这个,可以随便写,不过建议起名可以表示实际含义
创建表后删除约束
ALTER TABLE employee DROP FOREIGN KEY emp_dep_id
创建表后添加约束
ALTER TABLE employee ADD CONSTRAINT emp_dep_id FOREIGN KEY (uid) REFERENCES department(uid);
下面通过例子来看看外键的效果
比如employee与department,加了一个uid为3
然而department里的uid没有3故出错
这说明从表的外键列名字段不可出现主表的对应列中没出现的值
补充:级联操作
这个操作可以实现:当department中那个uid的2改为3时,employee中的uid中的所有2也自动改为3这就是级联更新
当department中那个uid的2删除时,employee中的uid中的2对应所有记录也自动删除,这就是级联删除,这里不演示,可以根据给的语法自行演示
1. 添加级联操作
语法:ALTER TABLE 表名 ADD CONSTRAINT 外键名称
FOREIGN KEY (外键字段名称) REFERENCES 主表名称(主表列名称) ON UPDATE CASCADE ON DELETE CASCADE ;
2. 分类:
1. 级联更新:ON UPDATE CASCADE
2. 级联删除:ON DELETE CASCADE
下面总结下在创建标后删除使用Modify且要用到drop关键字的有主键,唯一约束,外键,而外键比较复杂建议单独练习记忆
六.多表操作
1. 多表之间的关系
1. 分类:
1. 一对一(了解):
* 如:人和身份证
* 分析:一个人只有一个身份证,一个身份证只能对应一个人
2. 一对多(多对一):
* 如:部门和员工
* 分析:一个部门有多个员工,一个员工只能对应一个部门
3. 多对多:
* 如:学生和课程
* 分析:一个学生可以选择很多门课程,一个课程也可以被很多学生选择
2. 实现关系:
1. 一对多(多对一):
* 如:部门和员工
* 实现方式:在多的一方建立外键,指向一的一方的主键。
2. 多对多:
* 如:学生和课程
* 实现方式:多对多关系实现需要借助第三张中间表。中间表至少包含两个字段,这两个字段作为第三张表的外键,分别指向两张表的主键
3. 一对一(了解):
* 如:人和身份证
* 实现方式:一对一关系实现,可以在任意一方添加唯一外键指向另一方的主键。
实现的例子
注意我的外键设置的表
一对多:
CREATE TABLE department(
id INT PRIMARY KEY,
dep_name VARCHAR(10)
);
CREATE TABLE employee(
id INT PRIMARY KEY,
NAME VARCHAR(10),
eid INT,
CONSTRAINT emp_dep_id FOREIGN KEY (eid) REFERENCES department(id)
);
一对一:
CREATE TABLE IdCard(
id INT PRIMARY KEY,
number VARCHAR(20)
);
CREATE TABLE person(
id INT PRIMARY KEY,
NAME VARCHAR(10),
pid INT,
CONSTRAINT per_card_id FOREIGN KEY (pid) REFERENCES IdCard(id)
);
多对多:以学生表和课程为例
外键放在中间表里
CREATE TABLE student(
id INT PRIMARY KEY,
NAME VARCHAR(10)
);
CREATE TABLE course(
id INT PRIMARY KEY,
NAME VARCHAR(10)
);
CREATE TABLE mid_table(
sid INT ,
cid INT,
CONSTRAINT mid_stu_id FOREIGN KEY (sid) REFERENCES student(id),
CONSTRAINT mid_cour_id FOREIGN KEY (cid) REFERENCES course(id)
);
七.三大范式
* 概念:设计数据库时,需要遵循的一些规范。要遵循后边的范式要求,必须先遵循前边的所有范式要求
设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。
* 分类:
1. 第一范式(1NF):每一列都是不可分割的原子数据项
2. 第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于码(在1NF基础上消除非主属性对主码的部分函数依赖)
* 几个概念:
1. 函数依赖:A-->B,如果通过A属性(属性组)的值,可以确定唯一B属性的值。则称B依赖于A
例如:学号-->姓名。 (学号,课程名称) --> 分数
2. 完全函数依赖:A-->B, 如果A是一个属性组,则B属性值得确定需要依赖于A属性组中所有的属性值。
例如:(学号,课程名称) --> 分数
3. 部分函数依赖:A-->B, 如果A是一个属性组,则B属性值得确定只需要依赖于A属性组中某一些值即可。
例如:(学号,课程名称) -- > 姓名
4. 传递函数依赖:A-->B, B -- >C . 如果通过A属性(属性组)的值,可以确定唯一B属性的值,在通过B属性(属性组)的值可以确定唯一C属性的值,则称 C 传递函数依赖于A
例如:学号-->系名,系名-->系主任
5. 码:如果在一张表中,一个属性或属性组,被其他所有属性所完全依赖,则称这个属性(属性组)为该表的码
例如:该表中码为:(学号,课程名称)
* 主属性:码属性组中的所有属性
* 非主属性:除过码属性组的属性
3. 第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
举例分析三大范式:
该表不符合第一范式因为系这一字段名下还有两个分别为系名与系主任,不是原子项
这样就符合了:
但是又不满足第二范式:
分析步骤如下,先找到主属性组(码)即学号与课程名称
但是姓名,系名,系主任只依赖于学号,存在非主属性的部分函数依赖
变成下面的就可以了:
第一张图已经满足了三大范式,但是第二张图还有问题
存在传递依赖
系主任需要根据系名来决定,换成下面即可
最后这张表变成了三张均满足三大范式
八.数据库的备份和还原
* 备份: mysqldump -u用户名 -p密码 数据库名称 > 保存的路径
* 还原:
1. 登录数据库
2. 创建数据库
3. 使用数据库
4. 执行文件,source 文件路径
备份:
注意,如果登入了MySQL要先退出才可以使用
还原:
除了命令行方式还可以在Sqlyog直接用,这里就不介绍了
九.多表查询
先创建要用的表
# 创建部门表
CREATE TABLE dept(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
);
INSERT INTO dept (NAME) VALUES ('开发部'),('市场部'),('财务部');
# 创建员工表
CREATE TABLE emp (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
gender CHAR(1), -- 性别
salary DOUBLE, -- 工资
join_date DATE, -- 入职日期
dept_id INT,
FOREIGN KEY (dept_id) REFERENCES dept(id) -- 外键,关联部门表(部门表的主键)
);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('孙悟空','男',7200,'2013-02-24',1);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('猪八戒','男',3600,'2010-12-02',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('唐僧','男',9000,'2008-08-08',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('白骨精','女',5000,'2015-10-07',3);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('蜘蛛精','女',4500,'2011-03-14',1);
1. 内连接查询
隐式内连接
即使用where条件消除无用数据
SELECT * FROM emp,dept WHERE emp.dept_id = dept.id;
起别名的方式:
SELECT et.id,et.name FROM emp et,dept dt WHERE et.dept_id = dt.id;
显示内连接
语法: select 字段列表 from 表名1 [inner] join 表名2 on 条件
SELECT et.id,et.name FROM emp et inner join dept dt on et.dept_id = dt.id;
SELECT et.id,et.name FROM emp et join dept dt on et.dept_id = dt.id;
2. 外连接查询:
左外连接
语法:select 字段列表 from 表1 left [outer] join 表2 on 条件;
注意左表的全部查到再加上在条件下的
SELECT et.id,et.name,dt.id,dt.name FROM emp et LEFT OUTER JOIN dept dt ON et.dept_id = dt.id;
右外连接
* 语法:select 字段列表 from 表1 right [outer] join 表2 on 条件
注意右表的全部查到再加上在条件下的
SELECT * FROM dept t2 RIGHT JOIN emp t1 ON t1.dept_id
= t2.id
;
3. 子查询:
select name,salary from emp where emp.salary = (select max(salary) from emp)
核心思想:子查询可作为虚拟表参与查询
在需要查子表的字段时必须给子表起个名然后使用 表名.字段,即使是*也要用 表名.*
十.事务
此表为例
事务三大操作
1. 开启事务: start transaction;
2. 回滚:rollback;
3. 提交:commit;
START TRANSACTION;
UPDATE employee SET money=100 WHERE NAME = 'jack’
接下来
START TRANSACTION;
UPDATE employee SET money=1000 WHERE NAME = ‘jack’;
rollback
没有变1000
接下来:
START TRANSACTION;
UPDATE employee SET money=1000 WHERE NAME = ‘jack’;
commit
变回去了
事务提交的两种方式
* 事务提交的两种方式:
* 自动提交:
* mysql就是自动提交的
* 一条DML(增删改)语句会自动提交一次事务。
* 手动提交:
* Oracle 数据库默认是手动提交事务
* 需要先开启事务,再提交
* 修改事务的默认提交方式:
* 查看事务的默认提交方式:SELECT @@autocommit; -- 1 代表自动提交 0 代表手动提交
* 修改默认提交方式: set @@autocommit = 0;手动提交相当于开启事务,但是执行完语句后未进行
如果查询得到的会使修改后的数据
这里不再演示
事务四大特征
1. 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败。
2. 持久性:当事务提交或回滚后,数据库会持久化的保存数据。
3. 隔离性:多个事务之间。相互独立。
4. 一致性:事务操作前后,数据总量不变
事务的隔离级别(了解)
概念:发生在多个事务同时操作同一个数据发生的问题
涉及的三个问题:
1. 脏读:一个事务,读取到另一个事务中没有提交的数据
2. 不可重复读(虚读):在同一个事务中,两次读取到的数据不一样。
3. 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。(mysql无法演示)
隔离级别:
1. read uncommitted:读未提交
* 产生的问题:脏读、不可重复读、幻读
2. read committed:读已提交 (Oracle)
* 产生的问题:不可重复读、幻读
3. repeatable read:可重复读 (MySQL默认)
* 产生的问题:幻读
4. serializable:串行化
* 可以解决所有的问题
* 注意:隔离级别从小到大安全性越来越高,但是效率越来越低
* 数据库查询隔离级别:
* select @@tx_isolation;
* 数据库设置隔离级别:
* set global transaction isolation level 级别字符串;(设置后对于可视化软件要重新连接才可生效,
如果是命令行则要重新开个窗口方可生效)
非重点内容不作演示