数据库知识点
- 数据库相关概念
- mysql安装与使用
- navicat的使用
- SQL语言的查询(重点)
- 高级(了解)
一、数据库基本概念
数据库是什么
数据存储
1.人工管理阶段
- 结绳记事
- 甲骨
- 纸
人工阶段的数据存储使用起来不方便,不便于查询、共享、保存
2.文件系统阶段
- 磁盘
将数据存储在磁盘上,数据都存在文件中,查询很不方便
3.数据库系统阶段
- 数据库
长期存储在计算机内,有组织的数据集合,数据按照不同的分类存储到不同的表中,查询非常方便
RDBMS
Relational Database Managment System
关系型数据库系统
通过表来表示关系
- 当前主要有两种数据库,关系型数据库和非关系型数据库
- 所谓关系型数据库RDBMS ,是建立在关系模型的基础上的数据库,借助于集合代数等数学方法和概念来处理数据库中的数据
- 查看数据库排名 DB-Engines Ranking
关系型数据库核心元素
- 数据行(一条记录)
- 数据列(字段)
- 数据表(数据行集合)
- 数据库(数据表集合,一个数据库能有多个数据表)
SQL
Structured Query Language
结构化查询语言
在数据库中进行操作的语言,称为sql,结构化查询语言,当前关系型数据库都支持使用sql语言进行操作。
- SQL语言主要分为:
- DQL,数据查询语言,用于对数据进行查询,如select
- DML,数据操作语言,对数据进行增加、修改、删除,如insert、update、delete
- TPL,事务处理语言,对事务进行处理,包括begin transaction、commit、rollback
- DCL,数据控制语言,进行授权于权限回收,如grant、revoke
- DDL,数据定义语言,进行数据库、表的管理,如creat、drop
- CCL,指针控制语言,通过控制指针完成表的操作,如declare cursor
- 对于测试工程师,重点是数据查询,需要熟练编写DDL,其他语言如TPL、DCL、CCL了解即可
- SQL是一门特殊的语言,专门用来操作关系型数据库
- SQL不区分大小写
MySQL
是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,后被Sun公司收购,Sun公司后被Oracle公司收购,所以现在是Oracle旗下的产品。
特点:开源 免费 使用范围广 支持多平台
二、MySQL的安装与使用
MySQL下载中,已包含服务端和客户端
Linux平台下安装
Windows平台下安装
MacOS平台下安装
1.从MySQL官网下载安装包
-
拉到最下面MySQL Community Edition
-
选择MySQL Community Server
-
选择历史版本5.7
-
选择dmg格式
-
开始下载
2.安装
-
各种继续
-
复制最后一步的密码,是mysql的初始密码
3.启动MySQL服务端
-
系统偏好设置-->MySQL
-
启动/停止MySQL服务
4.修改密码
- 打开终端
- 输入命令:
cd /usr/local/mysql/bin
- 输入命令:
mysql -u root -p
- 输入初始密码(安装的最后一步时,让记住的密码)
- 输入命令:
FLUSH PRIVILEGES;
- 输入命令:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';
(MyNewPass处输入你的新密码)
5.配置环境变量
因为mysql的可执行命令在/usr/local/mysql/bin目录下,而这个目录不在普通用户的环境路径下,因此每次执行时都需要输入完整路径,比较麻烦。因此需要将这个路径添加到环境变量中。
打开终端
输入命令:
vim .bash_profile
-
在.bash_profile文件中加入
#配置mysql环境变量 export PATH=${PATH}:/usr/local/mysql-5.7.26-macos10.14-x86_64/bin
输入命令:
source .bash_profile
进行更新-
输入命令:
mysql -u root -p
以及新设置的密码,出现welcome……吧啦吧啦表示环境变量配置成功遇到的问题
因为自己的Terminal,装了zsh+iTerm,所以它默认启动时执行的脚本文件是~/.zshrc
文件,这就导致了每次关闭终端后,都需要重新source .bash_profile
mysql配置才能生效
解决:
mac使用zsh后,文件.bash_profile中的配置无效
6.启动MySQL客户端
MySQL自带的客户端是命令行界面,其实前面已经操作过。
- 输入命令
mysql -u root -p
和密码以root身份启动MySQL的客户端 - 在终端中出现mysql>,可以进行对数据库的操作
mysql>
7.使用Navicat连接MySQL服务端
-
Navicat安装
一般来说,测试常用的是图形界面的MySQL客户端,如Navicat。但是Navicat是收费软件,可试用14天,可以安装破解版,如果需要mac破解版的可以联系我。
三、Navicat的使用
连接数据库
(1)选择数据库类型
服务端是什么数据库就选择什么数据库(MySQL)
(2)填写连接信息(到公司问开发索要)
- 连接名:区分要接触到的各种环境,如测试环境、演示环境、生产环境
- 主机名或IP地址:MySQL服务端所在的IP,因为我们是在本机上安装并启动了MySQL服务,所以写localhost
- 端口号:默认是3306
-
用户名、密码:具备相应权限的用户名和密码(上文提到的root及修改后的密码)
(3)连接
此时是未连接状态,灰色。双击进行连接。
数据库操作
-
新建数据库
右键-新建数据库>>数据库名/选择默认字符集/默认排序规则
-
新建表
右键-新建表>>至少填写一个字段(name)>>保存为表(表名hero)
-
存一条数据
右键-打开表>>点击➕(增加)>>输入字段内容>>点击✅(完成)
- 修改一条数据
双击修改 - 删除一条数据
选中要删除的数据>>点击➖
数据表操作
-
改表
-
添加表字段
点击➕>>写入字段名>>保存
- 删除表字段
选中删除行>>点击➖>>保存
数据类型与约束
-
常用数据类型
-
整数 int
-2^31 (-2,147,483,648) 到 2^31 - 1 (2,147,483,647) ,无符号的范围是0到4294967295。
- 小数 decimal decimal(5,2),共存5位数,小数占2位
- 字符串 varchar varchar(3),最多存3个字符,一个中文或一个英文都是一个字符
- 日期时间 datetime
tips:数据类型的取值范围可以通过命令查看
mysql -u root -p
-
help 数据类型
如help int
,表示int的取值范围
-
-
约束
-
主键(primary key):物理上存储的顺序。
不能重复的一列且必须有值。
自动递增从1开始,删除一条数据,主键依然被占用。
一般作为主键使用时,int类型+自动递增+无符号
-
非空(not null):此字段不允许填空值
不能不填值。
字段后面勾选不是null,即表示该字段不允许填空值。
唯一(unique):此字段不允许重复
跟主键有点类似,值不重复。但主键是用来唯一标识一条信息。同一张表只能有一个主键,但能有多个唯一约束;-
默认值(default):当不填写此值时会使用默认值,如果填写时以填写为准
外键(foreign key):维护两个表之间的关联关系
【属于高级内容,后面讲】
-
数据库的备份与恢复
-
备份
-
右键>>转储SQL文件>>结构+数据
-
保存为一个.sql文件
-
.sql文件里存的是SQL语句和数据
-
-
恢复
- 新建一个数据库
选择与要恢复的表相同的字符集和默认排序规则 - 右键>>运行SQL文件>>选择要恢复的.sql文件
- 刷新
- 新建一个数据库
三、SQL语言
查询编辑器介绍
- 注释 ctrl+/
- 修改注释的颜色 偏好设置>>字体和颜色>>编辑器颜色
- 选中要运行的语句,右键选择“运行已选择的”
数据表操作
- 创建表
create table 表名 ( 字段名 类型 [约束], 字段名 类型 [约束] …… )
-- 创建一个newHero表 CREATE TABLE newHero ( id int unsigned primary key auto_increment, name VARCHAR(10), age int unsigned, height decimal(5,2), contact varchar(10) not null )
- 删除表
格式一:drop table 表名
表名存在就删除,表名不存在就报错
格式二:drop table if exists 表名
表名存在就删除,表名不存在也不报错,一般使用格式二,搭配在create语句前面写。
drop table if exists hero;
create table hero (
id int unsigned primary key auto_increment,
name VARCHAR(10),
age int unsigned,
height decimal(5,2),
contact varchar(10) not null
)
数据操作-增删改
增
格式一:所有字段设置值,值的顺序与表中字段顺序对应
insert into 表名 values (……);
说明:主键列自动增长,插入时要占位,通常使用0或者defualt或者null来占位
insert into newHero values (default,'小鲁班',15,140.55,'tony');
insert into newHero values (0,'小亚瑟',20,185.00,'tony');
insert into newHero values (null,'小守约',18,180.00,'herry');
格式二:指定字段设置值,值的顺序跟给出的字段对应
insert into 表名(字段名1,字段名2,……) values (字段值1,字段值2,……);
-- 添加一行数据 --
insert into newHero(name,contact) values('小文姬','relics');
-- 添加多行数据 --
insert into newHero(name,contact) values('小露娜','luna'),('小悟空','merry');
改
格式:update 表名 set 列1=值1,列2=值2……where 条件
-- 修改name为小鲁班的身高为135.00,年龄为12 --
update newHero set height=135.00,age=12 where name='小鲁班';
删
格式:delete from 表名 where 条件
-- 删除id为7的这条数据 --
delete from newHero where id=7;
逻辑删除:对于重要的数据 ,不能轻易执行delete语句进行删除,一旦删除,数据无法恢复,这时可以进行逻辑删除。
1.给表添加字段,代表数据是否删除,一般起名isdeleted,0代表未删除,1代表删除,默认值为0。
2.当要删除某条数据时,只需要设置isdeleted字段的值为1
3.以后查询数据时,只查询出isdeleted为0的数据
数据操作-查询
创建表
drop table if exists students;
create table students(
studentNo varchar(10) primary key,
name varchar(10),
sex varchar(1),
hometown varchar(20),
age tinyint(4),
class varchar(10),
card varchar(20)
)
准备数据
insert into students values ('001','王昭君','女','北京','20','1班','340322199001249654'),
('002','诸葛亮','男','上海','20','2班','340322199002242345'),
('003','张飞','男','南京','24','3班','340322199003242045'),
('004','白起','男','安徽','19','2班','340322199004249999'),
('005','大乔','女','天津','18','3班','340322199005242343'),
('006','孙尚香','女','安徽','24','2班','340322199006241233'),
('007','小乔','女','山西','20','2班','340322199007246789'),
('008','百里飞','男','河南','25','2班','340322199008242345'),
('009','百里守约','男','河南','30','2班',''),
('010','妲己','女','贵州','20','1班',null);
查询所有字段
select * from 表名;
例:
select * from students;
查询指定字段
- 在select后面的列名部分,可以使用as为列起别名,这个别名出现在结果集中。
select 列1,列2,...from 表名;
--表名.字段名
select students.name,students.age from students;
--可以通过as给表起名
select s.name,s.age from students as s;
--如果是单表查询可以省略表名
select name,age from students;
--用as给字段起别名
select name as 姓名,age as 年龄 from students;
--查询性别有哪几种
select distinct sex from students;
消除重复行
- 在select后面列前使用distinct可以消除重复的行
select dictinct 列1,...from 表名;
例:
--sex 去重
select distinct sex from students;
--sex+age的组合去重
select distinct sex,age from students;
条件查询
- 使用where子句对表中的数据筛选,符号条件的数据会出现在结果集中。
- 语法如下:
select 字段1,字段2... from 表名 where 条件;
例:
select * from students where id=1;
-
where后面支持多种运算符,进行条件的处理
- 比较运算
- 逻辑运算
- 模糊查询
- 范围查询
- 空判断
-
比较运算符
- 等于: =
- 大于: >
- 大于等于: >=
- 小于: <
- 小于等于: <=
- 不等于: != 或<>
-- 查询小乔的年龄 select age from students where name='小乔'; -- 查询年龄在20岁一下的同学的名字 select name from students where age<20; -- 查询家乡不在天津的同学的名字 select name from students where hometown!='天津';
-
逻辑运算符
- and
- or
- not
---查询年龄小于20的女同学 select * from students where age<20 and sex='女'; ---查询非天津的学生 select * from students where not hometown '天津';
-
模糊查询
- like 结合%和_搭配使用
- % 表示任意多个任意字符
- _表示一个任意字符
--查询姓百里的同学 select * from students where name like '百里%'; --查询姓百里且名只有一个字的同学 select * from students where name like '百里_'; --查询名字中包含有里的同学 select * from students where name like '%里%';
-
范围查询
- in表示在一个非连续的范围内
- between...and...表示在一个连续的范围内
--查询家乡是北京或上海或广州的学生 select * from students where hometown in('北京','上海','广州'); --查询年龄为18至22的学生 select * from students where age between 18 and 22;
-
空判断
注意
null
与''
是不同的判空is null
--查询没有填写身份证的同学 select * from students where card is null;
- 判非空is not null
--查询填写了身份证的同学 select * from students where card is not null;
排序查询
- 为了方便查看数据,可以对数据进行排序
- 语法
select * from 表名
order by 列1 asc|desc,列2 asc|desc,...;
- 将行数据按照列1进行排序,如果某些行列1的值相同时,则按照列2排序,以此类推
- 默认按照列值从大到小排列,默认升序
- asc从小到大,升序排列
- desc 从大到小,降序排列
--查询所有学生信息,按年龄从小到大排列
select * from students order by age;
--查询所有学生信息,按年龄从大到小排列,年龄相同时,再按学号从小到大排列
select * from students order by age desc,studentNo asc;
--查询所有学生信息,按姓名从a-z排序(对中文进行排序)
select * from students order by convert(name using gbk);
聚合函数
- 为了快速得到统计数据,经常会使用到如下5个聚合函数
- count(*)表示计算总行数,括号中写星与列名,结果都是相同的
- 聚合函数不能在where中使用
--计数count(*)
--查询学生总数
select count(*) from students;
--max(列)表示求此列最大值
--查询女生的最大年龄
select max(age) from students where sex='女';
--min(列)表示求此列最大值
--查询1班的最小年龄
select min(age) from students where class='1班';
--sum(列)表示求此列的和
-- 查询北京的学生的年龄总和
select sum(age) from students where hometown='北京';
--avg(列)表示求此列的平均值
--查询女生的平均年龄
select avg(age) from students where sex='女';
分组
- 按照字段分组,表示此字段相同的数据会被放到一个组中
- 分组后,分组的依据列会显示在结果中,其他列不会显示在结果集中
- 可以对分组后的数据进行统计,做聚合运算
- 语法
select 列1,列2,聚合... from 表名 group by 列1,列2,…;
--查询各种性别的人数
select sex,count(*) from students group by sex;
--查询各种年龄的人数
select age,count(*) from students group by age;
--查询各个班级学生的平均年龄、最大年龄、最小年龄
select class,avg(age),max(age),min(age) from students group by class;
--查询各班男女生人数
select class,sex,count(*) from students group by class,sex;
-
分组后过滤 having
语法:select 列1,列2,... from 表名 group by 列1,列2,... having 列1,列2,...聚合 ; --having后面的条件运算符与where一样
--查询男生的总人数 --方法1: select sex,count(*) from students where sex='男'; --方法2: select sex,count(*) from students group by sex having sex='男';
where与having 对比
where是对from后面指定的表进行数据筛选,属于对原始表的筛选
having是对group by的结果进行筛选
分页
获取部分行
- 当数据量过大时,在一页中查看数据是一件非常麻烦的事情
- 语法
select * from 表名 limit strat,count
- 从strat开始,获取count条数据
- start索引从0开始
--查询前3行学生信息 select * from students limit 0,3 --查询第4行到第6行学生信息 select * from students limit 3,3
分页
-- 需求分页, 每页3条数据 --
-- 总共有多少条 10条
select count(*) from students;
-- 10/3 获取总页数,共4页
-- 第一页 --3(1-1)
select * from students limit 0,3;
-- 第二页 --3(2-1)
select * from students limit 3,3;
-- 第三页 --3(3-1)
select * from students limit 6,3;
-- 第四页 --3(4-1)
select * from students limit 9,3;
- 分页功能实现原理就是,点击按钮时,执行对应的sql,每个sql语句的起始位置不一样。
连接查询
- 当查询结果的列来源于多张表时,需要将多张表连接成一个大的数据集,再选择合适的列返回
-
等值连接查询:查询结果为两个表匹配到的数据
-
左连接:查询到的结果为两个表匹配到的数据加左表特有的数据,对于右表中不存在的数据使用null填充
-
右连接:查询到的结果为两个表匹配到的数据加右表特有的数据,对于左表中不存在的数据使用null填充
准备数据
drop table if exists courses;
create table courses(
courseNo int(10) unsigned primary key auto_increment,
name varchar(10)
)
insert into courses values
('1','数据库'),
('2','qtp'),
('3','linux'),
('4','系统测试'),
('5','单元测试'),
('6','测试过程');
drop table if exists scores;
create table scores(
id int(10) unsigned primary key auto_increment,
courseNo int(10),
studentNo varchar(10),
score tinyint(4)
);
insert into scores VALUES
('1','1','001','90'),
('2','1','002','75'),
('3','2','002','98'),
('4','3','001','86'),
('5','3','003','80'),
('6','4','004','79'),
('7','5','005','96'),
('8','6','006','80');
-
等值连接
- 方式一
select * from 表1,表2 where 表1.列=表2.列;
此方式会产生笛卡尔积,生成的记录总数=表1的总数X表2的总数,会产生临时表。- 笛卡尔积原理
1.先确定数据要用到哪些表。(表1,表2)
2.将多个表先通过笛卡尔积变成一个表
select * from 表1,表2
,表1的每一行X表2的每一行
3.然后去除不符合逻辑的数据(根据两个表的关系去掉)
表1.列=表2.列
4.最后当做是一个虚拟表一样来加上条件即可
- 笛卡尔积原理
- 方式二(内连接)
select * from 表1 inner join 表2 on 表1.列=表2.列;
- 内连接是先判断是否符合
表1.列=表2.列
再生成结果 - 不会产生临时表,性能高
- 内连接是先判断是否符合
--查询学生信息及学生成绩 -两种方法 SELECT * FROM students stus, scores sco WHERE stus.studentNo = sco.studentNo; -------- SELECT stus. NAME, sco.score FROM students stus INNER JOIN scores sco ON stus.studentNo = sco.studentNo; -- 查询课程信息及课程的成绩 select * from courses cou, scores sco where cou.courseNo=sco.courseNo; ------- select * from courses cou inner join scores sco on cou.courseNo=sco.courseNo; -- 查询学生信息及学生的课程对应的成绩(3表查询) select * from students stu,courses cour,scores sco where stu.studentNo=sco.studentNo and cour.courseNo=sco.courseNo; ----- select * from students stu inner join scores sco on stu.studentNo=sco.studentNo inner join courses cour on cour.courseNo=sco.courseNo; -- 查询王昭君的成绩,要求显示姓名、课程名、成绩 select stu.name as 姓名,cour.name as 课程名,score 成绩 from students stu inner join scores sco on stu.studentNo=sco.studentNo inner join courses cour on cour.courseNo=sco.courseNo where stu.name ='王昭君'
- 方式一
左连接
select * from 表1
left join 表2 on 表1.列=表2.列
--查询所有学生的成绩,包括没有成绩的学生(2表查询)
select
*
from
students stu
left join scores sco on stu.studentNo=sco.studentNo
对于左表不存在的数据用null
填充
-- 查询所有学生的成绩,包括没有成绩的学生,显示课程名(3表查询)
select
stu.name,sco.score,cour.courseNo
from
students stu
left join scores sco on stu.studentNo=sco.studentNo
left join courses cour on cour.courseNo=sco.courseNo
- 右连接
select * from 表1
right join 表2 on 表1.列=表2.列
为了便于练习,在此数据库加入两条数据:
insert into courses values
(0,'语文'),
(0,'数学')
--查询所有课的成绩,包括没有成绩的课程(2表查询)
select
*
from
scores sco
right join courses cour on cour.courseNo=sco.courseNo;
--查询所有课程的成绩,包括没有成绩的课程,包括学生信息(3表查询)
select
*
from
scores sco
right join courses cour on cour.courseNo=sco.courseNo
left join students stu on sco.studentNo=stu.studentNo;
-- 注意区分要让左边全显示还是右边全显示
练习
-- 查询所有学生的成绩 包括没有成绩的学生,显示课程名
select
stu.name,cour.name,score
FROM
students stu
left join scores sco on stu.studentNo=sco.studentNo
left join courses cour on sco.courseNo=cour.courseNo;
自关联
- 表中的某一列,关联了这个表的另外一列,但是它们的业务逻辑含义是不一样的。
编号 | 城市 | 上级编号 |
---|---|---|
01 | 湖南省 | |
02 | 长沙市 | 01 |
03 | 岳阳市 | 01 |
05 | 陕西省 | |
06 | 西安市 | 05 |
07 | 咸阳市 | 05 |
准备数据
drop table if exists areas;
create table areas(
aid int primary key,
atitle varchar(20),
pid int
);
insert into areas values
('130000','河北省',NULL),
('130100','石家庄市','130000'),
('130400','邯郸市','130000'),
('130600','保定市','130000'),
('130700','张家口市','130000'),
('130800','承德市','130000'),
('410000','河南省',null),
('410100','郑州市','410000'),
('410300','洛阳市','410000'),
('410500','安阳市','410000'),
('410700','新乡市','410000'),
('410800','焦作市','410000');
--查询一共有多少个省
select count(*) from areas where pid is null;
--查询河南省所有城市(自关联2次)
select
*
from
areas pro,areas city
where
pro.aid=city.pid and pro.atitle='河南省';
添加区县数据
insert into areas values
('410101','中原区','410100'),
('410102','二七区','410100'),
('410103','金水区','410100');
--查找河南省所有区县(关联3次)
select * from areas pro,areas city,areas qu
where pro.aid=city.pid and city.aid=qu.pid and pro.attle='河南省';
子查询
- 在一个select语句中,嵌入了另一个select语句,那么被嵌入的select语句称之为子查询语句
主查询:
- 主要查询的对象,第一条select语句
主查询和子查询的关系:
- 子查询是嵌入到主查询中的
- 子查询是辅助主查询的,要么充当条件,要么充当数据源
- 子查询是可以独立存在的,是一条完整的select语句
子查询的分类:
- 标量子查询:子查询返回的结果是一个数据(一行一列)
- 列子查询:返回的结果是一列(一列多行)
- 行子查询:返回的结果是一行(一行多列)
- 表级子查询:返回的结果是多行多列
标量子查询
--查询年龄大于平均年龄的学生
--方法1:
--1.求出平均年龄的值为22
select avg(age) from students;
--2.求age大于22的学生
select * from students where age > 22;
--方法2:
select * from students where age > (select avg(age) from students);
--ps:第一个select语句就是主查询,第二个select语句就是子查询
--查询王昭君的数据库成绩
select
score
from
scores
where
studentNo=(select studentNo from students where name ='王昭君')
and courseNo=(select courseNo from courses where name='数据库');
列级子查询
--查询20岁的学生的成绩,要求显示成绩
--方法1:
--1.求出age等于20的学号是001,002,007,010
select studentNo from students where age=18;
--2.求学号是005的成绩
select score from scores where studentNo in(001,002,007,010);
--方法2:
select score from scores where studentNo in(select studentNo from students where age);
行级子查询
--查询男生中年龄最大的学生信息
--方法1:标量子查询
select max(age) from students; --30
select * from students where sex='男' and age=(select max(age) from students);
--where后面条件都是且关系的,可以有另一种写法
select * from students where (sex,age)=('男','30');
--方法2:行级子查询
--1.返回sex,age(一行多列)
select sex,age from students where sex='男' order by age desc limit 1;
--2.
select
*
from
students
where
(sex,age)=(select sex,age from students where sex='男' order by age desc limit 1);
表级子查询
- 标量子查询、列级子查询、行级子查询都是作为where条件,而表级子查询是作为数据源。
--查询数据库和系统测试的成绩
--方法1:
select * from courses
inner join scores on courses.courseNo=scores.courseNo
where courses.name in('数据库','系统测试');
--先连接了两个表,再筛选,连接两表时,多了很多无效数据。
--方法2:
select * from scores a
inner join (select courseNo from courses where name in('数据库','系统测试')) b
on a.courseNo=b.courseNo;
--直接连接筛选后的表,会快一些
子查询中特定的关键字
- in 范围
- 格式:主查询 where 条件 in(列子查询)
- any | some 任意一个
- 格式:主查询 where 列=any(列子查询)
- 在条件查询的结果中匹配任意一个即可,
=any
等价于in
- all
- 格式:主查询 where 列=all(列子查询):等于里面所有
- 格式:主查询 where 列<>all(列子查询):不等于其中所有
查询演练
-- 求所有学生的平均成绩,保留两位小数
select round(avg(score),2) as 平均成绩 from scores;
-- 查询年龄大于平均年龄的学生,并按年龄降序排序
select * from students
where age >(select avg(age) from students) order by age desc;
-- 查询年龄大于王昭君的学生,并按年龄降序排列
select * from students
where age>(select age from students where name='王昭君') order by age desc;
数据分表
-
一个表中某一列出现了重复的内容,叫冗余内容,采用数据分表,减少内存。
如下表,笔记本类型,出现了大量重复文字。
可以增加一个新表,类型表,来存储笔记本所有类型,给类型加上编号,需要用到笔记本类型时,填入编号。
另一个好处,如果笔记本类型变了,只用改类型表即可。
四、数据库高级
数据库设计
E-R模型
E-R模型的基本元素是:实体、联系和属性
- E表示entry,实体:一个数据对象,描述具有相同特征的事物
- R表示relationship,联系:表示一个或多个实体之间的关联关系,关系的类型包括一对一、一对多、多对多
- 属性:实体的某一特性称为属性
关系也是一种数据,需要通过一个字段存储在表中
1.实体A对实体B为1对1,则在表A或表B中创建一个字段,存储另一个表的主键。(让使用频率少的表来维护关系)
2.实体A对实体B为1对多:在表中创建一个字段,存储表A的主键值(让"多"的一方的表来维护关系)
3.实体A对实体B为多对多:新建一个表C, 这个表只有两个字段,一个用于存储A的主键值,一个用于存储B的主键值。(让中间表C来维护关系)
命令行客户端
windows
- 程序-MySQL-MySQL server-MySQL Commandline Client
- 输入密码
mac
- 进入bin目录
cd /usr/local/mysql-5.7.26-macos10.14-x86_64/bin
- 输入命令
mysql -u root -p
和密码以root身份启动MySQL的客户端 - 在终端中出现mysql>,可以进行对数据库的操作
mysql>
常用命令
-
展示所有的数据库
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | testing01 | +--------------------+ 5 rows in set (0.00 sec)
-
使用某个数据库
mysql> use testing01; Database changed
-
使用select语句
mysql> select * from students; ps:使用select语句之前必须先use要使用的数据库,否则会报错 --- mysql> select * from students; ERROR 1046 (3D000): No database selected
-
查看当前使用的数据库
mysql> select database(); +------------+ | database() | +------------+ | testing01 | +------------+ 1 row in set (0.00 sec)
-
创建数据库
create database 数据库名 charset=utf8;
mysql> create database testing02 charset=utf8; Query OK, 1 row affected (0.01 sec)
-
删除数据库
drop database 数据库名;
mysql> drop database testing02; Query OK, 0 rows affected (0.02 sec)
-
查看当前数据库所有表
mysql> show tables; +---------------------+ | Tables_in_testing01 | +---------------------+ | areas | | courses | | newHero | | scores | | students | | tech | +---------------------+ 6 rows in set (0.00 sec)
-
查看表结构
方法一: mysql> desc students; +-----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+-------------+------+-----+---------+-------+ | studentNo | varchar(10) | NO | PRI | NULL | | | name | varchar(10) | YES | | NULL | | | sex | varchar(1) | YES | | NULL | | | hometown | varchar(20) | YES | | NULL | | | age | tinyint(4) | YES | | NULL | | | class | varchar(10) | YES | | NULL | | | card | varchar(20) | YES | | NULL | | +-----------+-------------+------+-----+---------+-------+ 7 rows in set (0.01 sec) 方法二: mysql> show create table students; 展示创建students表的SQL语句。
-
中文乱码
mysql>set charset gbk;
备份和恢复
备份
- 进入bin目录
cd /usr/local/mysql-5.7.26-macos10.14-x86_64/bin
- 输入命令
mysqldump -u root -p密码 数据库名 > 备份路径;
mysqldump -u root -padmin1234 testing01>~/back.sql
恢复
- 先新建一个数据库 testing03
- 输入命令
mysql -uroot -padmin1234 testing03<~/back.sql
函数
-
字符串函数
拼接字符串 concat(str1,str2,...)
select name,hometown,CONCAT(name,'的家乡是',hometown) from students;
-
包含字符个数 length(str)
1个英文、数字、字符的length都是1,但是1个中文的length是3--查询名字是两个字的学生 select * from students where length(name)=6;
-
截取字符串
- left(str,len) 返回字符串str的左端len个字符
- right(str,len) 返回字符串str的右端len个字符
- substring(str,pos,len) 返回字符串str的位置pos起len个字符
--隐藏学生的名,只显示学生的姓氏 select concat(left(name,1),'**')from students;
-
去除空格
- ltrim(str) 返回删除了左空格的字符串str
- rtrim(str) 返回删除了右空格的字符串str
- ltrim(rtrim(str)) 左右空格都去掉
- trim(str) 左右空格都去掉
- 中间的空格没法去掉
-
大小写转换
- lower(str)
- upper(str)
select lower('aBadQ');
-
数学函数
求四舍五入的值
round(n,b)
n表示原数,d表示小数位数,默认为0
select round(1.555,2);
求x的y次幂
pow(x,y)
select pow(2,3);
获取圆周率
PI()
select PI();
随机数
rand()
,值为0-1.0的浮点数
select rand();
拓展:随机从一个表中获取一条记录
select * from students order by rand() limit 1;
-
日期时间函数
当前日期 current_date()
select current_date();
当前时间 current_time()
select current_time();
当前日期时间 now()
select now();
-
日期格式化 date_format(date,format)
select date_format(current_date(),'%Y-%M');
- 参数format可选值
%Y 获取年,返回完整年份 %y 获取年,返回简写年份 %m 获取月,返回月份 %d 获取日,返回天值 %H 获取时,返回24小时进制的小时数 %h 获取时,返回12小时进制的小时数 %i 获取分,返回分钟数 %s 获取秒,返回秒数
流程控制
- case语法:等值判断
- 说明:当值等于某个比较值的时候,对应的结果会被返回;如果所有的比较值都不相等则返回else的结果;如果没有else并且所有比较值都不相等则返回null
select case 1 when 1 then 'one' when 2 then 'two' else 'zero' end as result
--根据性别判断该称呼为先生还是女士 select case sex when '男' then concat(left(name,1),'先生') when '女' then concat(left(name,1),'女士') else concat(left(name,1),'大侠') end as result from students;
自定义函数
-
创建自定义函数
- 语法:
--设置分隔符 delimiter $$ --创建函数 create function 参数名称 (参数列表) return 返回类型 begin sql语句 end $$ --还原分隔符 delimter ;
- delimiter用于设置分隔符,分隔符就是告诉MySQL解释器,该段命令是否已结束,是否可执行。默认情况下,delimiter是分号
;
。在命令行客户端中,如果有一行命令以分号结束,那么回车后,mysql将会执行该命令。 - 在“sql语句”编写部分的语句需要以分号结尾,此时回车会直接执行,所以要创建存储过程前需要指定其他符号作为分隔符,此处使用
$$
,也可以使用其他字符。 - 最后要把delimter设置回来,
delimter ;
示例:
--函数功能:去掉字符串前面和后面的空格 DROP FUNCTION IF EXISTS my_trim; delimiter $$ create function my_trim(str varchar(100)) returns varchar(100) begin return ltrim(rtrim(str)); end; $$ delimiter ;
使用自定义函数
select my_trim(' ab d ');
存储过程
存储过程,也翻译为存储程序,是一条或多条SQL语句的集合
-
创建存储过程
- 语法
--设置分隔符 delimeter // --创建存储过程 create procedure 存储过程名称(参数列表) begin sql语句 end; // --还原分隔符 delimiter ;
- 示例
drop procedure if exists pro_stu; delimiter // create procedure pro_stu() BEGIN select * from students; end; // delimiter ;
-
调用存储过程
语法
call 存储过程(参数列表);
示例
call pro_stu();
存储过程和函数都是为了可重复执行操作数据库的sql语句的集合。
存储过程和函数都是经过一次编译,就会被缓存起来,下次使用就直接命中缓存中已经编译好的sql,不需要重复编译
减少网络交互,减少网络访问流量
视图
对于复杂的查询,在多个地方被使用,如果需求发生了改变,需要更改sql语句,则需要在多个地方进行修改,维护起来非常麻烦
解决:定义视图
视图本质就是对查询的封装
定义视图,建议以v_开头
create view 视图名称 as select语句;
示例:创建视图,查询学生对应的成绩信息
create view v_stu_sco_cour as
select
stu.name,sco.courseNo,sco.score
from
students stu
inner join scores sco on stu.studentNo=sco.studentNo
inner join courses cour on sco.courseNo=cour.courseNo;
使用视图
select * from v_stu_sco_cour;
show tables;
也能展示出视图还有一个用处是可以利用视图把真正的表名和字段名隐藏起来
create view v_students as
select name 姓名,age 年龄 from students;
事务
为什么要有事务
事务广泛的运用于订单系统、银行系统等多种场景
例如:A用户和B用户是银行的储户,现在A要给B转账500元,那么需要做以下几件事:
1.检查A的账户余额>500元
2.A账户中扣除500元
3.B账户中增加500元正常的流程是:A账户扣了500元,B账户加了500,皆大欢喜。那如果A账户扣钱之后,系统出了故障呢?A白白损失500元,而B也没有得到本该属于它的500元。这个案例,隐藏一个前提条件:A的钱和B的钱,要么同时成功,要么同时失败。
所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。例如银行转账:从一个账号扣款并从另一个账号增款,这两个操作要么都执行,要么都不执行。所以,应该把他们看作一个事务。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。
--开启事务
begin;
所有操作都成功了;
--提交
commit;
--开启事务
begin;
任意一步操作失败了;
--回滚
rollback;
- 示例
mysql> select * from students where name in('大乔','小乔');
+-----------+--------+------+----------+------+-------+--------------------+
| studentNo | name | sex | hometown | age | class | card |
+-----------+--------+------+----------+------+-------+--------------------+
| 005 | 大乔 | 女 | 天津 | 18 | 3班 | 340322199005242343 |
| 007 | 小乔 | 女 | 山西 | 20 | 2班 | 340322199007246789 |
+-----------+--------+------+----------+------+-------+--------------------+
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update students set age=age+3 where name='大乔';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> update students set age=age-3 where name='小乔';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from students where name in('大乔','小乔');
+-----------+--------+------+----------+------+-------+--------------------+
| studentNo | name | sex | hometown | age | class | card |
+-----------+--------+------+----------+------+-------+--------------------+
| 005 | 大乔 | 女 | 天津 | 21 | 3班 | 340322199005242343 |
| 007 | 小乔 | 女 | 山西 | 17 | 2班 | 340322199007246789 |
+-----------+--------+------+----------+------+-------+--------------------+
2 rows in set (0.00 sec)
索引
一般应用系统对比数据库的读写比例在10:1左右,而且插入操作和更新操作很少出现性能问题,遇到最多的,也最容易引起问题的,还是一些复杂的查询操作,所以查询语句的优化显然是重中之重
当数据库中的数据量很大时,查找数据会变得特别慢
优化方案:索引
索引是作用在某个字段上的,where条件通过有索引的字段查询时,查询时间才会比较快。
-
示例
- 建测试数据
--建测试表 drop table if exists test_index; create table test_index( title varchar(10) default null ) --插入数据:通过excel造插入20000条数据的语句 insert into test_index values('test0'); insert into test_index values('test1'); …… insert into test_index values('test20000');
开启运行时间监控
set profiling=1;
查找第一万条数据 test10000
select * from test_index where title='test10000';
查看执行时间
show profiles;
//0.00880900s创建索引
create index title_index on test_index(title(10));
创建索引后再次查找第一万条数据 test10000
select * from test_index where title='test10000';
查看执行时间
show profiles
//0.00276300
语法
查看索引
show index from 表名;
-
创建索引
- 建表时创建索引
create table creat_index( id int primary key, name varchar(10) unique, age int, key (age) ); --会为primary key、unique自动创建索引,通过key(字段)也是创建索引。
- 对已经存在的表,添加索引
如果指定字段是字符串,需要指定长度,建议长度与定义字段的长度一样
字段类型不是字符串,可以不填写长度部分
create index 索引名称 on 表名(字段名称(长度)); 例: create index age_index on create_index(age); create index name_index on create_index(name(10));
删除索引
drop index 索引名称 on 表名;
查询分析
explain
select * from test_index where title='test10000';
- 有索引时查询分析:
- 删除索引后查询分析:
说明:key-有值表示有使用到索引;rows-表示查询了多少行,不准确,但能反应出有索引查询的行数减少。
缺点
索引虽然大大提高了查询速度,同时却会降低更新表的速度,如对表进行update\insert\delete,因为更新表时,MySQL不仅要保存数据,还要保存以下索引文件
但是 ,在互联网应用中,查询语句远远大于增删改的语句,甚至可以占到80-90%,所以不用太在意,只是大量数据导入时,可以先删除索引,再批量插入数据,最后再添加索引。
外键 foreign key
如果一个实体的某个字段指向另一个实体的主键,就成为外键。被指向的实体,称之为主实体(主表),也叫父实体(父表)。负责指向的实体,称之为从实体(从表),也叫子实体(子表)
对关系字段进行约束,当为从表中的关系字段填写值时,会到关联的主表中查询此表的值是否存在,如果存在则填写成功,如果不存在则填写失败并报错。
语法
查看外键
show create table 表名;
-
设置外键约束
- 创建数据表时设置外键约束
foreign key(自己的字段) reference 主表(主表字段);
create table class( id int unsigned primary key auto_increment, name varchar(10) ); create table stu( name varchar(10), class_id int unsigned, foreign key(class_id) reference class(id) );
- 对于已经存在的表设置外键约束
alter table 从表名 add foreign key (从表字段) references 主表名(主表字段);
alter table stu add foreign key (class_id) references class(id);
- 创建数据表时设置外键约束
删除外键
-- 需要先获取外键约束名称
show create table stu; --stu_ibfk_1
-- 获取名称之后就可以根据名称来删除外键约束
alter table 表名 drop foreign key 外键名称;
alter table stu drop foreign key stu_ibfk_1;
- 实际开发中很少使用外键约束,会极大降低表更新的效率。一般通过开发人员写代码来约束。
修改密码
- 使用root登录,修改mysql数据库的user表
- 使用password()函数进行密码加密
- 注意修改完后需刷新权限
use mysql;
--update user set authentication_string=password('新密码') where user='用户名';
--旧版本:update user set password=password('新密码') where user='用户名';
update user set authentication_string=password('123') where user='root';
--刷新权限
flush privileges;
忘记密码
- 配置mysql登录时不需要密码,修改配置文件
- centos中,配置文件位置/etc/my.cnf
- windows中,配置文件位置为安装目录..\MySQL Server 5.1\my.ini
找到mysqld,在它的下一行,添加skip-grant-tables
2.重启mysql,免密码登陆,修改mysql数据库的user表
use mysql;
--update user set authentication_string=password('新密码') where user='用户名';
--旧版本:update user set password=password('新密码') where user='用户名';
update user set authentication_string=password('123') where user='root';
--刷新权限
flush privileges;
3.改完之后,把配置文件改回去,删除skip-grant-tables,再重启mysql
mac忘记密码 实践有效
-
关闭mysql服务:
苹果->系统偏好设置->最下边点mysql 在弹出页面中 关闭mysql服务(点击stop mysql server)
进入终端输入:
cd /usr/local/mysql/bin/
登录管理员权限:
sudo su
输入以下命令来禁止mysql验证功能:
./mysqld_safe --skip-grant-tables &
mysql会自动重启(偏好设置中mysql的状态会变成running)
输入命令
./mysql
输入命令
FLUSH PRIVILEGES;
输入命令
SET PASSWORD FOR ['root'@'localhost'](mailto:'%20rel=) = PASSWORD('你的新密码');