数据库知识点

数据库知识点

  • 数据库相关概念
  • 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


    数据库知识点_第1张图片
  • 选择MySQL Community Server


    数据库知识点_第2张图片
    g
  • 选择历史版本5.7


    数据库知识点_第3张图片
  • 选择dmg格式


    数据库知识点_第4张图片
  • 开始下载


    数据库知识点_第5张图片

2.安装

  • 各种继续


    数据库知识点_第6张图片
  • 复制最后一步的密码,是mysql的初始密码


    数据库知识点_第7张图片

3.启动MySQL服务端

  • 系统偏好设置-->MySQL


    数据库知识点_第8张图片
  • 启动/停止MySQL服务


    数据库知识点_第9张图片

    数据库知识点_第10张图片

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_profilemysql配置才能生效
    解决:
    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)


数据库知识点_第11张图片

数据库知识点_第12张图片

(2)填写连接信息(到公司问开发索要)

  • 连接名:区分要接触到的各种环境,如测试环境、演示环境、生产环境
  • 主机名或IP地址:MySQL服务端所在的IP,因为我们是在本机上安装并启动了MySQL服务,所以写localhost
  • 端口号:默认是3306
  • 用户名、密码:具备相应权限的用户名和密码(上文提到的root及修改后的密码)
    (3)连接
    此时是未连接状态,灰色。双击进行连接。


    数据库知识点_第13张图片

数据库操作

  • 新建数据库
    右键-新建数据库>>数据库名/选择默认字符集/默认排序规则


    数据库知识点_第14张图片

    数据库知识点_第15张图片
  • 新建表
    右键-新建表>>至少填写一个字段(name)>>保存为表(表名hero)


    数据库知识点_第16张图片

    数据库知识点_第17张图片
  • 存一条数据
    右键-打开表>>点击➕(增加)>>输入字段内容>>点击✅(完成)


    数据库知识点_第18张图片
  • 修改一条数据
    双击修改
  • 删除一条数据
    选中要删除的数据>>点击➖

数据表操作

  • 改表


    数据库知识点_第19张图片
  • 添加表字段
    点击➕>>写入字段名>>保存


    数据库知识点_第20张图片
  • 删除表字段
    选中删除行>>点击➖>>保存

数据类型与约束

  • 常用数据类型

    • 整数 int
      -2^31 (-2,147,483,648) 到 2^31 - 1 (2,147,483,647) ,无符号的范围是0到4294967295。


      数据库知识点_第21张图片
    • 小数 decimal decimal(5,2),共存5位数,小数占2位
    • 字符串 varchar varchar(3),最多存3个字符,一个中文或一个英文都是一个字符
    • 日期时间 datetime

    tips:数据类型的取值范围可以通过命令查看

    • mysql -u root -p
    • help 数据类型
      help int,表示int的取值范围
  • 约束

    • 主键(primary key):物理上存储的顺序。
      不能重复的一列且必须有值。
      自动递增从1开始,删除一条数据,主键依然被占用。
      一般作为主键使用时,int类型+自动递增+无符号


      数据库知识点_第22张图片
    • 非空(not null):此字段不允许填空值
      不能不填值。
      字段后面勾选不是null,即表示该字段不允许填空值。


      数据库知识点_第23张图片
    • 唯一(unique):此字段不允许重复
      跟主键有点类似,值不重复。但主键是用来唯一标识一条信息。同一张表只能有一个主键,但能有多个唯一约束;

    • 默认值(default):当不填写此值时会使用默认值,如果填写时以填写为准


      数据库知识点_第24张图片

      数据库知识点_第25张图片
    • 外键(foreign key):维护两个表之间的关联关系
      【属于高级内容,后面讲】

数据库的备份与恢复

  • 备份

    • 右键>>转储SQL文件>>结构+数据


      数据库知识点_第26张图片
    • 保存为一个.sql文件


      数据库知识点_第27张图片
    • .sql文件里存的是SQL语句和数据


      数据库知识点_第28张图片
  • 恢复

    • 新建一个数据库
      选择与要恢复的表相同的字符集和默认排序规则
    • 右键>>运行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
    )
    

等同于:
数据库知识点_第29张图片
  • 删除表
    格式一: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语句的起始位置不一样。
连接查询
  • 当查询结果的列来源于多张表时,需要将多张表连接成一个大的数据集,再选择合适的列返回
  • 等值连接查询:查询结果为两个表匹配到的数据


    数据库知识点_第30张图片
  • 左连接:查询到的结果为两个表匹配到的数据加左表特有的数据,对于右表中不存在的数据使用null填充


    数据库知识点_第31张图片
  • 右连接:查询到的结果为两个表匹配到的数据加右表特有的数据,对于左表中不存在的数据使用null填充


    数据库知识点_第32张图片

准备数据


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填充

数据库知识点_第33张图片

-- 查询所有学生的成绩,包括没有成绩的学生,显示课程名(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;

数据分表

  • 一个表中某一列出现了重复的内容,叫冗余内容,采用数据分表,减少内存。
    如下表,笔记本类型,出现了大量重复文字。
    可以增加一个新表,类型表,来存储笔记本所有类型,给类型加上编号,需要用到笔记本类型时,填入编号。
    另一个好处,如果笔记本类型变了,只用改类型表即可。


    数据库知识点_第34张图片

    数据库知识点_第35张图片

四、数据库高级

数据库设计

E-R模型
E-R模型的基本元素是:实体、联系和属性

  • E表示entry,实体:一个数据对象,描述具有相同特征的事物
  • R表示relationship,联系:表示一个或多个实体之间的关联关系,关系的类型包括一对一、一对多、多对多
  • 属性:实体的某一特性称为属性
    关系也是一种数据,需要通过一个字段存储在表中
    1.实体A对实体B为1对1,则在表A或表B中创建一个字段,存储另一个表的主键。(让使用频率少的表来维护关系)

2.实体A对实体B为1对多:在表中创建一个字段,存储表A的主键值(让"多"的一方的表来维护关系)


数据库知识点_第36张图片

3.实体A对实体B为多对多:新建一个表C, 这个表只有两个字段,一个用于存储A的主键值,一个用于存储B的主键值。(让中间表C来维护关系)

数据库知识点_第37张图片

命令行客户端

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;

忘记密码

  1. 配置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('你的新密码');

你可能感兴趣的:(数据库知识点)