数据库(Database,DB)
:是按照数据结构来组织,存储和管理数据的仓库典型特征
:数据的结构化、数据间的共享、减少数据的冗余度,数据的独立性数据表
:数据表是关系数据库的基本存储结构,二维数据表有行(Row),和列(Column)组成,也叫作记录(行)和字段(列)
MySQL中的数据类型
MySQL数据类型与Java数据类型对照
– 完整的DQL语句顺序:
select
…
from
…
where
…
group by
…
having
…
order by
…
limit …
MySQL常用函数
代码如下(示例):
use myemployees;
-- 查询邮箱中包含a字符的每个部门的平均工资
select avg(salary),department_id
from employees
where email like '%a%'
group by department_id;
-- 查询有奖金的每个领导手下员工的最高工资
select max(salary),manager_id
from employees
where commission_pct is not null
group by manager_id;
-- 查询每个部门的员工个数>2
select count(*),department_id
from employees
group by department_id
having count(*)>2
-- 查询每个工种有奖金的员工的最高工资>12000的工作编号和最高工资
select job_id,max(salary)
from employees
where commission_pct is not null
group by job_id
having max(salary) > 12000;
-- 查询领导编号>102的每个领导手下的最低工资>5000的领导编号是哪个,以及其最低工资
select manager_id,min(salary)
from employees
where manager_id > 102
group by manager_id
having min(salary) > 5000;
代码如下(示例):
-- 查询员工信息,要求先按工资排序,再按员工编号排序,由高到低
select * from employees
order by salary desc,employee_id desc;
-- 查询员工的姓名和部门号和年薪,按年薪降序,按姓名升序
select last_name,department_id,salary*12*(1+ifnull(commission_pct,0)) 年薪
from employees
order by 年薪 desc,last_name asc;
-- 选择工资不在8000到17000的员工的姓名和工资,按工资降序
select last_name,salary
from employees
where salary not between 8000 and 17000
order by salary desc;
-- 查询邮箱中包含e的员工信息,并先按邮箱的字节数降序,再按部门号升序
select *
from employees
where email like '%e%'
order by length(email) desc,department_id asc;
-- 按年薪的高低显示员工的信息和年薪 【按表达式排序】
select *,salary*12*(1+ifnull(commission_pct,0)) 年薪
from employees
order by salary*12*(1+ifnull(commission_pct,0)) desc;
-- 按员工姓名的长度显示员工的姓名和工资【按函数排序】
select length(last_name) 长度,last_name,salary
from employees
order by length(last_name) desc;
MySQL连接查询
代码如下(示例):
-- in() any()其中任意一个 all()所有 exists()
-- 查询location_id是1400或1700的部门编号
select distinct department_id
from departments
where location_id in(1400,1700);
-- 查询工种比job_id为“IT_PROG"工种'任一'工资低的员工的员工号、姓名、job_id 以及 salary
select employee_id,last_name,job_id,salary
from employees
where salary < any( -- 小于工种为“IT_PROG"其中一个则满足条件
select salary from employees where job_id = 'IT_PROG'
) and job_id <> 'IT_PROG';
-- 查询工种比job_id为“IT_PROG"工种'所有'工资低的员工的员工号、姓名、job_id 以及 salary
select employee_id,last_name,job_id,salary
from employees
where salary < all( -- 小于所有工种为“IT_PROG"则满足条件
select salary from employees where job_id = 'IT_PROG'
) and job_id <> 'IT_PROG';
代码如下(示例):
-- 查询员工表中编号最小,工资最高的员工
select *
from employees
where employee_id = (
select min(employee_id) from employees
) and salary = (
select max(salary) from employees
);
代码如下(示例):
-- 查询每个部门的员工个数 (行查询)
select d.*,(
select count(*)
from employees e
where e.department_id = d.department_id
) 个数
from departments d;
-- 查询每个部门的员工个数 (外连接)
select d.*,count(employee_id) 个数
from employees e
right join departments d
on e.department_id = d.department_id
group by d.department_id;
代码如下(示例):
-- 查询每个部门的平均工资的工资等级
select ag_dep.*,g.grade_level
from (
select avg(salary) ag,department_id
from employees
group by department_id
) ag_dep -- 给表取别名
inner join job_grades g
on ag_dep.ag between lowest_sal and highest_sal;
代码如下(示例):
-- 查询有员工的部门名
select department_name
from departments d
where exists( -- 判段符合里面内容
select *
from employees e
where d.department_id = e.department_id
);
-- 查询没有女朋友的男神信息 (not exists)
select b.*
from boys b
where not exists( -- 判段不符合里面内容
select boyfriend_id
from beauty g
where g.id = b.boyfriend_id
)
-- 查询没有女朋友的男神信息 (not in)
select b.*
from boys b
where b.id not in (
select boyfriend_id from beauty
);
代码如下(示例):
-- limit 起始位置,每页条数
-- 起始位置是从0开始算起!
-- 标准的分页sql
每页显示3条记录
第1页:0,3
第2页:3,3
第3页:6,3
第4页:9,3
第5页:12,3
每页显示pageSize条记录
第pageNum页:(pageNum-1)*pageSize,pageSize
-- 查询前5名学生
select studentno,studentname
from student
limit 5;
select studentno,studentname
from student
limit 0,5;
-- 查询6-10名学生
select studentno,studentname
from student
limit 5,5;
代码如下(示例):
#union可以去重
#union all 不去重
-- 查询并且的三种方法:
select username from user where username = 'zhangsan' or username = 'lisi';
select username from user where username in ('zhangsan','lisi');
select username from user where username = 'zhangsan'
union
select username from user where username = 'lisi';
-- 查询部门编号>90或邮箱包含a的员工信息
select * from employees where department_id > 90
union
select * from employees where email like '%a%';
-- 查询中国用户中男性的信息以及外国用户中男性的信息
select id,cname,csex from t_ca where csex = '男'
union
select t_id,t_name,t_gender from t_ua where t_gender = 'male';
-- 查询中国用户中男性的信息以及外国用户中男性的信息
select id,cname from t_ca where csex = '男'
union all -- 查询两个表的id和name相同的话也会显示
select t_id,t_name from t_ua where t_gender = 'male';
代码如下(示例):
-- 往boys表中同时插入多个数据
insert into boys (boyName,userCP)
values('张三',200),('李四',400),('王五',700);
-- 修改没有男朋友的女神的男朋友编号都为2号
update boys b
right join beauty g
on g.boyfriend_id = b.id
set g.boyfriend_id = 2
where b.id is null;
-- 删除黄晓明的信息以及他女朋友的信息
delete b,g
from boys b
inner join beauty g on b.id = g.boyfriend_id
where b.boyName = '黄晓明';
#delete删除表后自增从断点继续,有返回值
#truncate删除表后自增从1开始,没有返回值
delete from boys;
truncate table boys;
扩展:
-- =或<>不能用于判断null值,is null或is not null可以判断null值 -- 由于更新的数据中没有主键会报错,更新前面加上这一句 SET SQL_SAFE_UPDATES = 0; -- 查询员工表的job_id中包含a和e的,并且a在e的前面 select job_id from employees where job_id like '%a%e%'; -- 分组函数不可直接使用在where子句中 select name from user where sal > avg(sal); -- 会发生语法错误!!! -- 分组函数自动忽略NULL select sum(sal) from user where sal is not null; -- 后面不需要写is not null判断,因为分组函数自动忽略NULL! count(*):统计总记录条数 count(字段):统计字段中不为NULL的数据总条数 -- where和having 能使用where的就使用,因为效率高,对原始数据进行过滤,having效率低 不能使用where的就使用having,可以对分组后的数据进行过滤 查询每个部门的最高薪资,要求显示薪资大于2900的部门编号: select deptno,max(sal) from emp where sal > 2900 group by deptno; -- 效率高 select deptno,max(sal) from emp group by deptno having sal > 2900; -- 效率低 查询每个部门的平均薪资,要求显示平均薪资大于2000的部门编号: select deptno,avg(sal) from emp group by deptno having avg(sal) > 2000; -- 可行 select deptno,avg(sal) from emp where avg(sal) > 2000 group by deptno; -- 不可行,where后不能分组函数
代码如下(示例):
-- 创建数据库
create database if not exists test;
-- 删除数据库
drop database if exists test;
-- 创建表
drop table if exists stuinfo;
CREATE TABLE stuinfo (
id INT PRIMARY KEY,#主键
stuName VARCHAR(20) NOT NULL,#非空
gender CHAR(1) CHECK (gender = '男' OR gender = '女'),#检查
seat INT UNIQUE,#唯一
age INT DEFAULT 18,#默认
majorId INT,
CONSTRAINT fk_stuinfo_major FOREIGN KEY (majorId)#外键约束
REFERENCES major (id)
);
CREATE TABLE IF NOT EXISTS major (
id INT PRIMARY KEY,
majorName VARCHAR(20)
);
-- 查看表结构
desc stuinfo;
-- 查看表的索引
show index from stuinfo;
-- 修改列的约束
alter table stuinfo modify column stuName varchar(20) not null; #非空
alter table stuinfo modify column age int default 18; #默认
alter table stuinfo modify column id int primary key; #主键
alter table stuinfo add constraint fk_stuinfo_major FOREIGN KEY(majorId) references major(id); #主键
什么是索引?
怎么创建索引对象?删除索引对象?
删除索引对象:drop index 索引名 on 表名
什么时候考虑给字段添加索引?
主键和具有unique约束的字段会自动添加索引
根据主键查询效率较高
索引底层采用的数据结构是:B+Tree
索引的实现原理?
通过B+Tree缩小扫描范围,底层索引进行了排序、分区,索引会携带数据在表中的“物理地址”,最终通过索引检索到数据之后,获取到关联的”物理地址“,通过“物理地址”定位表中的数据,效率是最高的。
索引的分类
索引什么时候失效?
练习
代码如下(示例):
use school;
-- 插入100万数据.
DELIMITER $$ -- 写函数之前必须要写,标志
CREATE FUNCTION mock_data ()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
INSERT INTO app_user(`name`,`email`,`phone`,`gender`,`password`,`age`)VALUES(CONCAT('用户',i),'[email protected]',CONCAT('18',FLOOR(RAND()*(999999999-100000000)+100000000)),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));
SET i=i+1;
END WHILE;
RETURN i;
END $$
SELECT mock_data(); -- 查看函数
-- 未创建索引查询
SELECT * FROM app_user where name = '用户9999'; --2.031 sec / 0.000 sec
-- 创建索引
create index app_user_name on app_user(name);
-- 查看执行计划
explain SELECT * FROM school.app_user where name = '用户9999';
-- 创建索引后执行效率提高很多
SELECT * FROM app_user where name = '用户9999'; --0.031 sec / 0.000 sec
MySQL事务的操作
什么是视图
视图就是站在不同角度去看到数据。(同一张表的数据通过不同的角度去看待)
视图操作
创建视图只能是查询语句(DQL), 对视图进行CRUD操作,会影响到原表数据。
create view 视图名 as select 字段名 from 表名
drop view 视图名
代码如下(示例):
-- 创建视图
CREATE VIEW myview1 AS SELECT username,age FROM user;
-- 查看视图
SELECT * FROM myview1;
-- 通过视图操作表数据
INSERT INTO myview1 (username,age) VALUES('zhangsan',18);
INSERT INTO myview1 (username,age) VALUES('lisi',18);
INSERT INTO myview1 (username,age) VALUES('wangwu',18);
SET SQL_SAFE_UPDATES = 0; -- 由于更新的数据中没有主键
UPDATE myview1 SET age = 19 WHERE username = 'lisi';
DELETE FROM myview1 WHERE username = 'wangwu';
-- 查看原表数据
SELECT * FROM user;
视图的作用
视图可以隐藏表的实现细节。保密级别较高的系统,数据库只对外提供相关的视图,程序员只对视图对象进行CRUD操作。
比如:视图对字段进行取别名,隐藏原表字段名
数据导出
直接在CMD中输入命令:(当然文件名可以随便)
导出整个数据库:
mysqldump -u root -p 数据库名 > 数据库名.sql
mysqldump -u root -p 数据库名 > D:\数据库名.sql
导出数据库中指定的表数据:
mysqldump -u root -p 数据库名 表名 > D:\数据库名.sql
数据导入
进入mysql中先创建数据库再导入数据
create database test;
use test;
source D:\数据库名.sql
什么是设计范式?
设计表的依据,按照三范式设计的表不会出现数据冗余。
三范式
第一范式(1NF):强调的是列的原子性,任何一张表都应该有主键,数据库中每一列都是不可分割的原子数据项
第二范式(2NF):建立在第一范式的基础上,要求全部非主关键字段完全依赖于主键,不能产生部分依赖
多对多,三张表,关系表要加外键
student(学生表) teacher(教师表) student_teacher_relation(学生教师关系表)
sno(pk) sname tno(pk) tname id(pk) sno(pk) tno(fk)
———————————— ———————————— ———————————————————
1 张三 1 李老师 1 1 3
2 李四 2 王老师 2 1 1
3 王五 3 张老师 3 2 2
4 2 3
5 3 2
第三范式(3NF):建立在第二范式的基础上,任何非主关键字段依赖于主键,不能产生传递依赖
一对多,两张表,多的表要加外键
class(班级表) student(学生表)
cno(pk) cname sno(pk) sname classno(fk)
———————————— ———————————————————
1 班级1 101 张三 1
2 班级2 102 李四 1
103 王五 2
104 赵六 2
提醒
实际开发中,以满足客户的需求为主,有的时候会拿冗余换执行速度(以空间换时间)。
一对一如何设计
有两种方案:主键共享和外键唯一