MySQL基础大总结(配有数据库文件)

MySQL基础

文章框架概览

思维导图

在这里插入图片描述

数据库练习文件下载链接(不需要积分)

请点击我

一、数据库概述

1. 相关概念

  • DB: Database 存储数据的仓库,保存了一系列有组织的数据
  • DBMS:数据库管理系统。数据库是通过DBMS创建和操作的容器。MySQL,SQL server,Oracle,DB2
  • SQL:结构化查询语言,专门用来与数据库通信的语言
    • SQL优点
      • 几乎所有的DBMS都支持SQL
      • 简单,使用灵活

2. 使用数据库的好处

  • 实现数据持久化存储
  • 实现结构化查询,易于管理

3. 查看MySQL版本

两种方式,一种是通过bash查看,另一种是通过MySQL命令查看

  • 提供bash查看

    mysql -V
    mysql --version
    
  • 通过MySQL命令查看

    select version();
    

4. MySQL导入导出数据

4.1 导入数据

4.1.1 bash中通过命令导入

mysql -u用户名 -p密码 < 要导入的数据库文件(test.sql)

举例

mysql -uroot -p123456 < test.sql

4.1.2 source 命令导入

source 命令导入数据库需要先登录到数库终端

source 路径;

举例:导入桌面文件夹MySQL中的test.sql文件

source ~/Desktop/MySQL/test.sql;

4.2 导出数据

4.2.1 使用select … into outfile 语句导出数据

4.2.1.1 语法

简单导出

select * from 表名 into outfile 'filename';
# 把account 表中的数据导入到 /var/lib/mysql-files/
select * from account into outfile  '/var/lib/mysql-files/account.txt';

导出csv格式的文件
生成一个文件,各值用逗号隔开

select * from account into outfile '/var/lib/mysql-files/account.txt'
fields terminated by ',' 
enclosed by '"'
lines terminated by '\r\n';
  • SELECT…INTO OUTFILE 'file_name’形式的SELECT可以把被选择的行写入一个文件中。该文件被创建到服务器主机上,因此您必须拥有FILE权限,才能使用此语法。
  • 输出不能是一个已存在的文件。防止文件数据被篡改。
  • 你需要有一个登陆服务器的账号来检索文件。否则 SELECT … INTO OUTFILE 不会起任何作用。
  • 在UNIX中,该文件被创建后是可读的,权限由MySQL服务器所拥有。这意味着,虽然你就可以读取该文件,但可能无法将其删除。
4.2.1.2 导入文件提示 --secure-file-priv option 问题

错误提示:

ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so i        t cannot execute this statement

原因:因为在安装MySQL的时候限制了导入与导出的目录权限。只允许在规定的目录下才能导入。

查看secure-file-priv当前的值

show variables like "secure_file_priv";

在这里插入图片描述
本地value的值:

  • (1)NULL,表示禁止。
  • (2)如果value值有文件夹目录,则表示只允许该目录下文件(测试子目录也不行)。
  • (3)如果为空,则表示不限制目录。

解决

  • (1)把导入路径改为secure-file-priv对应的value中的文件夹目录
  • (2)把secure-file-priv的value值修改为准备导入文件的放置路径
  • (3)修改配置文件去掉导入的目录限制。可修改mysql配置文件(Windows下为my.ini, Linux下的my.cnf)
    • 在[mysqld]下面,查看是否有:secure_file_priv = 如上这样一行内容,如果没有,则手动添加。
    • 如果存在如下行:secure_file_priv = /var/lib/mysql-files 这样一行内容,表示限制为/var/lib/mysql-files文件夹。
    • 如果存在如下行 secure_file_priv = 这样一行内容,表示不限制目录,等号一定要有,否则mysql无法启动。
    • 修改完配置文件后,重启mysql生效。
      • 关闭:service mysqld stop
      • 启动:service mysqld start

4.2.2 使用mysqldump导出SQL格式的数据

mysqldump 是 mysql 用于转存储数据库的实用程序。它主要产生一个 SQL 脚本,其中包含从头重新创建数据库所必需的命令 CREATE TABLE INSERT 等。

mysqldump -uroot -p 数据库名 表名 > 文件名
# 回车后会提示你输入密码
password:

举例:把practice.sql中的account表导入到桌面

mysqldump -uroot -p practice account > ~/Desktop/account.txt
password:xxxxxxxx

5. MySQL Ubuntu安装

  • 1)sudo apt update
  • 2)sudo apt-get install mysql-server mysql-client
  • 3)安装过程中需要你输入MySQL 管理员用户(root)密码
  • 4)(非必须)运行MySQL初始化安全脚本 sudo mysql_secure_installation
    mysql_secure_installation脚本设置的东西:更改root密码、移除MySQL的匿名用户、禁止root远程登录、删除test数据库。使用上面的这些选项可以提高MySQL的安全

二、DQL 数据查询语言

1. 基础查询

语法

  • 普通查询:Select 查询列表 from 表名;
  • 去重查询:Select distinct 字段 from 表名; 不能是多个字段

注意

  • 查询列表:可以是表中的字段(多个字段用‘,’隔开),常量值,表达式,函数;
  • 字符型和日期型必须用单引号引起,数值型不需要
  • 查询的结果是一个虚拟的表格

2. 条件查询

select 查询列表 from 表名 where 条件;
  • 执行顺序 3,1,2。先从表里查,然后过滤条件,最后执行select
  • 逻辑运算符用于连接条件运算符
    在这里插入图片描述
  • 模糊查询:like 与通配符搭配使用;%任意多个字符,_任意单个字符
  • \:转义字符;在语句后面加上ESCAPE ‘字符’可指定这个字符为转移字符
    在这里插入图片描述
  • Between … and … 包含临界值
  • in列表的值类型必须一致,in不支持通配符
  • 安全等于 <=> :可以用于判断null值与普通类型的值,=不能用于判断null值;

3. 排序查询

select 查询列表 from 表名 [where  条件] order by 排序列表 [asc | desc];
  • sec升序,默认值;desc降序
  • order by子句支持单个字段,多个字段,表达式,函数,别名
  • 按多个字段排序,比如先按年薪降序,按姓名升序
    一般放在查询语句后面,limit子句除外

4. 常见函数

select 函数名(实参列表) [from 表名];

4.1 单行函数

4.1.1 字符函数

函数 说明
length(‘str’) 返回字符长度
upper(参数) 将字符变成大写
lower(参数) 将字符变成小写
concat(str1,str2,…) 拼接字符串
substr(str,pos) 返回pos开始的字符串
substr(str,pos1,pos2) 返回pos1开始到pos2的字符串
instr(str,substr) 返回子字符串在字符串中的第一次出现的索引位置,找不到返回0
trim(‘字符’ from ‘str’) 去除str中开始和结尾的字符,默认为空格
lpad(‘str’,n,‘字符’) 用指定的字符实现左填充指定长度
rpad(‘str’,n,‘字符’) 右填充
replace(str,substr1,substr2) 用substr2替换substr1
  • Utf8下一个英文字母一个字节,一个汉字3个字节
    在这里插入图片描述
  • SQL中索引从1开始
    在这里插入图片描述
  • 左填充
    在这里插入图片描述
    案例:查询邮箱的用户名
select substr(email,1,instr(email,'@')-1) 用户名;

4.1.2 数学函数

函数 说明
round(数值) 四舍五入
round(数值,n) 保留n位小数
ceil(数值) 向上取整
floor(数值) 向下取整
truncate(数值,n) 截断,取n位小数,小数位数小于n时返回原数值
mod(n1,n2) 取余,被除数为负数,结果为负数;a-a/b*b
rand() 获取随机数,0-1之间的小数

4.1.3 日期函数

函数 说明
now() 返回当前系统日期+时间
curdate() 返回当前系统日期3
curtime() 返回当前系统时间
year(now()) 返回当前系统的 年
year(‘日期’) 返回日期的年份
month(‘日期’) 数字
monthname(‘日期’) 英文
日,时分秒都可以
str_to_date() 将日期格式的字符转换成指定格式的日期
date_format() 将日期转换成字符
datediff(日期1,日期2) 计算两个日期之间差的天数

在这里插入图片描述
在这里插入图片描述

4.1.4 流程控制函数

4.1.4.1 if 函数
  • 语法
    if(表达式1,表达式2,表达式3);
    
  • 执行顺序
    • 如果表达式1成立,返回表达式2的值,否则返回表达式3的值
4.1.4.2 Case 函数

(一) 相当于switch case,实现等值判断

case 要判断的字段或表达式  
when 常量1  then  要显示的值1或语句1;
when 常量2  then  要显示的值2或语句2;
......
else 要显示的值n或语句n;
end;#返回的是值
end case;# 返回的是语句

(二)相当于多重if,实现区间判断

case 
when 条件1 then 要显示的值1或语句1;
when 条件1 then 要显示的值1或语句1;
......
else 要显示的值n或语句n;
end;#返回的是值
end case;# 返回的是语句

特点:

  • 可以作为表达式,嵌套在其他语句中使用,可以放在任何地方,begin end中或之外
  • 可以作为独立的语句使用,只能放在begin end 中
  • when中的值或条件成立,则执行对应then后面的语句,并结束case;都不满足则执行else中的语句或值
  • else语句可以省略,如果省略了else并且when中其他条件都不满足,则返回NULL

4.1.5 其他函数

函数 说明
version() 返回当前MySQL版本
database() 返回当前使用的数据库
user() 返回当前用户

md5(‘字符’) I 返回字符的md5形式
ifnull(字段,0);|判断某字段或表达式是否为NULL,为NULL则返回指定值,否则返回原数;
isnull(字段);| 判断某字段是否为NULL,是则返回1,否则返回0

4.2 多行函数

也被称为统计函数,聚合函数,组函数,分组函数

函数 说明
Sum 求和
Avg 求平均
Max 求最大值
Min 求最小值
Count 计数
  • Sum,avg一般用于数值型,而max,min,count可以用于任何类型
  • 所有分组函数都忽略null
  • 可以与distinct搭配实现去重运算,sum(distinct,字段);
  • count函数
    • Count(字段);统计字段中的个数
    • Count(*) ; 可以用来计算总行数
    • Count(1);相当于count(*),括号内可以是常量,结果一样;
  • MyISAM存储引擎下,count(*)效率高;InnoDB存储引擎中count(*)与count(1)效率差不多,但是比count(字段)效率高
  • 和分组函数一同查询的字段一般要求是group by后的字段

5. 分组查询

5.1 语法

# 语法:
	select 分组函数,列 (要求出现在group by的后面)
	from 表名
	[where 条件]
	group by 分组的列表
	[having 分组后的筛选]
	[order by 子句]
/*
注意:
	查询列表必须特殊,要求是分组函数和 group by 后出现的字段 
	执行顺序5,1,2,3,4,6
*/

案例:查询每个工种的最高工资
在这里插入图片描述

5.2 分类

类别 数据源 位置 关键字
分组前筛选 原始表 group by 之前 where
分组后筛选 分组后结果 group by 之后 having
  • 分组函数作为条件肯定放在having子句中
  • 能用分组前筛选的优先选择分组前筛选
  • group by 子句支持单个字段分组,多个字段分组(多个字段分组时,就把多个字段都放在group by后面,表示多个字段一致时才分为一组),表达式或函数(用的比较少)
  • 可以添加排序,需要放在整个分组查询的最后

5.2.1 添加分组前筛选

直接在group by 前加上where条件

案例:查询姓名中出现a字符的,每个部门的平均工资
在这里插入图片描述

5.2.2 添加分组后筛选

having 用于分组后的筛选

案例:查询哪个部门的员工数大于2,分两步走

  • 计算每个部门的员工个数
  • 利用第一步的结果求那个部门员工数大于2
    在这里插入图片描述

6. 连接查询

也称为多表查询

数据:
boys:
在这里插入图片描述
beauty:
在这里插入图片描述

6.1 笛卡尔乘积现象

笛卡尔乘积现象:表1 有m行,表二有n行,结果有m*n行
原因:没有有效的连接条件
避免:添加合适的连接条件

通过beauty表中的boyfriend_id找到boys表中对应的名称

select name,boyName from beauty,boys;

这样写会出现笛卡尔乘积错误,因为没有加上任何连接条件,就会使得beauty中的每一条记录与boys中的每条记录匹配。如果beauty有12条,boys有4条,那么最后的出来的记录有48条
解决:添加合适的连接条件,让beauty表中的boyfriend_id与boys中的id相对应

select name,boyName from beauty,boys where beauty.boyfriend_id = boys.id;

6.2 连接查询分类

  • 按年代分类

    • sql92标准:MySQL中仅仅支持内连接
    • sql99标准(推荐)MySQL中支持内连接+外连接(左外和右外)+交叉连接
  • 按功能

    • 内连接
      • 等值连接
      • 非等值连接
      • 自连接
    • 外连接
      • 左外连接
      • 右外连接
      • 全外连接(MySQL不支持)
    • 交叉连接

在 SELECT, UPDATE 和 DELETE 语句中使用 Mysql 的 JOIN 来联合多表查询。

  • inner join(内连接,或等值连接):获取两个表中字段匹配关系的记录。
  • left join(左连接):获取左表所有记录,即使右表没有对应匹配的记录。
  • right join(右连接): 与 left join 相反,用于获取右表所有记录,即使左表没有对应匹配的记录
    在这里插入图片描述
    在这里插入图片描述

6.3 SQL92——内连接

SQL92中MySQL只支持内连接

6.3.1 等值连接

6.3.1.1 案例

案例1:查询beauty表中女生对应boys表中的男朋友(girl.sql)

select name,boyName 
from beauty,boys 
where beauty.boyfriend_id = boys.id;

案例2:查询员工名、工种号、工种名(myemployees.sql)

select e.last_name,e.job_id,j.job_title 
from jobs j,employees e 
where e.job_id = j.job_id;
  • 可以在from后为表起别名,减少复杂程度;起别名后原表名称不再起作用
  • 表的顺序也可以改变

案例3:添加分组 查询每个城市的部门个数(myemployees.sql)

select count(*),city
from departments as d,locations as l
where d.location_id = l.location_id
group by city;

案例4:三表连接,查询员工名,部门名和所在的城市

select last_name,department_name,city 
from employees e,departments d,locations l 
where e.department_id = d.department_id 
and d.location_id = l.location_id;
6.3.1.2 等值连接总结
  • 等值连接的结果为多表连接的交集部分
  • n表连接,至少需要n-1个连接条件‘
  • 多表连接的顺序没有要求
  • 一般需要为表起别名
  • 可以搭配前面介绍的所有子句使用,比如排序,分组,筛选

6.3.2 非等值连接

连接条件不是等号

  • 可以搭配前面介绍的所有子句使用,比如排序,分组,筛选

案例1:查询员工的工资和工资级别
工资级别是个区间范围
在这里插入图片描述

select salary,grade_level 
from employees e,job_grades g 
where salary between g.lowest_sal and g.highest_sal;

6.3.3 自连接

自己连接自己,不与其他表连接查询;所需要的信息都在同一张表中

案例1:查询员工名,及对应的上级名
在这里插入图片描述

把同一张表当作两张表进行处理,赋予别名以进行区分

select e.employee_id,e.last_name,m.employee_id,m.last_name 
from employees as e,employees as m 
where e.manager_id = m.employee_id;

在这里插入图片描述

6.4 SQL99

6.4.1 语法

select 查询列表
from1 别名 
[连接类型] join2 别名
on 连接条件
[where 筛选条件]
[group by 分组]
[having 筛选条件]
[order by 排序列表]

连接类型

  • 内连接:inner
  • 外连接:
    • 左外连接:left [outer]
    • 右外连接:right [outer]
    • 全外连接:full [outer] outer可省略
  • 交叉连接:cross

6.4.2 内连接

6.4.2.1 等值连接

注意:

  • 可以添加排序,分组,筛选等
  • inner 可以省略
  • 筛选条件放在where 后面,连接条件放在on后面,提高分离性,便于阅读
  • inner join 连接与sql92的等值连接结果相同
  • 内连接的结果是两个表的交集

案例1:查询员工名,部门名

select last_name,department_name
from employees e

inner join departments d

on e.department_id = d.department_id;

案例2:查询名字中包含e的员工名和工种名(添加筛选)

select last_name,job_title
from employees e

inner join jobs j
on e.job_id = j.job_id

where e.last_name like '%e%';

案例3:查询部门个数大于3的城市名和部门个数 (分组+筛选)

select city,count(*) as 部门个数
from departments d

inner join locations l
on d.location_id = l.location_id

group by city
having count(*) > 3;

案例4:查询员工名、部门名、工总名,并按部门排序 (三表连接)

select last_name,department_name,job_title
from employees e

inner join departments d
on e.department_id = d.department_id

inner join jobs j
on e.job_id = j.job_id

order by department_name desc;
6.4.2.2 非等值连接

案例1:查询员工的工资级别

select salary,grade_level
from employees e
join job_grades g
on e.salary between g.lowest_sal and g.highest_sal;

案例2:查询工资级别的个数>20的个数,并按工资级别降序

select count(*),grade_level
from employees e

join job_grades g
on e.salary between g.lowest_sal and g.highest_sal

group by grade_level

having count(*) > 20

order by grade_level desc;
6.4.2.3 自连接

案例:查询员工姓名及上级姓名

select e.last_name,e.manager_id,m.last_name,m.employee_id
from employees e

inner join employees m

on e.manager_id = m.employee_id; 

6.4.3 外连接

应用场景:

  • 查询一个表中有,另一个表中没有的情况

特点:

  • 外连接的查询结果为主表中的所有记录
    • 如果从表中有和他匹配的,则显示匹配的值
    • 如果从表中没有和他匹配的,则显示NULL
    • 外连接查询结果 = 内连接结果 + 主表中有 而没有的记录
  • 左外连接,left join 左边的是主表
  • 右外连接,right join右边的是主表
  • 左外和右外交换两个表的顺序,可以实现同样的效果
  • 全外连接 = 内连接 + 表1有表2无 + 表1无表二有;相当于并集
  • 全外连接,两边都是主表

案例1:查询 男朋友 不在 boys表中 的 女神名

# 左外连接
select b.name
from beauty b
left outer join boys
on b.boyfriend_id = boys.id
where boys.id is null; 
# 因为外连接查询结果 = 内连接结果 + 主表中有  而没有的记录   且boys表中的id为主键
# 右外连接
select b.name
from boys
right outer join beauty b
on b.boyfriend_id = boys.id
where boys.id is null; 
# 因为外连接查询结果 = 内连接结果 + 主表中有  而没有的记录   且boys表中的id为主键

案例2:查询哪个部门没有员工

# 左外连接
select d.*,employee_id
from departments d
left outer join employees e
on d.department_id = e.department_id
where e.employee_id is null;
# 右外连接
select d.*,employee_id
from employees e
right outer join departments d
on d.department_id = e.department_id
where e.employee_id is null;

6.4.4 交叉连接

就是beauty表与boys表的笛卡尔乘积

select b.*,boys.*
from beauty b
cross join boys

7. 子查询

7.1 概述

7.1.1 相关定义

出现在其他语句中的select语句,称为子查询或内查询
内部嵌套其他select语句的查询,称为主查询或外查询

7.1.2 分类

按子查询出现的位置

  • select 后面:仅仅支持标量子查询
  • from 后面 :支持表子查询
  • where 或 having 后面 : 支持标量子查询、列子查询、行子查询(较少)
  • exists 后面 (相关子查询):支持表子查询

按结果集的行列数不同

  • 标量子查询(结果集只有一行一列,单行)
  • 列子查询(一列多行,多行)
  • 行子查询(一行多列)
  • 表子查询(一般为多行多列)

7.2 where或having后面

特点

  • 子查询放在小括号内
  • 子查询一般放在条件的右侧
  • 标量子查询,一般搭配着单行操作符(< > >= <= <> =)使用
  • 列子查询,一般搭配多行操作符(in,any/some,all)使用
  • 子查询的执行优先于主查询

7.2.1 标量子查询(单行子查询)

案例1:谁的工资比Abel高?

第一步:查询Abel的工资

# 一行一列
select salary
from employees
where last_name = 'Abel';

第二步:查询员工信息,满足salary > 第一步结果

select *
from employees
where salary > (
	select salary
	from employees
	where last_name = 'Abel'
);

案例2:返回job_id与141号员工相同,且salary比143号员工多的 员工姓名,job_id和工资
第一步:查询141号员工的job_id

# 一行一列
select job_id
from employees
where employee_id = 141;

第二步:查询143号员工的salary

# 一行一列
select salary
from employees
where employee_id = 143;

第三步:查询job_id与141号员工相同,且salary比143号员工多的 员工姓名,job_id和工资

select last_name,job_id,salary
from employees
where job_id = (
	select job_id
	from employees
	where employee_id = 141
) and salary > (
	select salary
	from employees
	where employee_id = 143
);

案例3:返回公司工资最少的员工的last_name,job_id,salary
第一步:查询公司的 最低工资

select min(salary) 
from employees;

第二步:查询工资等于最低工资的员工的last_name,job_id,salary

select last_name,job_id,salary
from employees
where salary = (
	select min(salary) 
	from employees
);

案例4:查询最低工资大于 50号部门最低工资 的 部门id和其最低工资
第一步:查询50号部门的最低工资

select min(salary)
from employees
where department_id = 50; 

第二步:查询每个部门的最低工资

select min(salary)
from employees
group by department_id;

第三步:对第二步的结果进行筛选,满足salaly > 第一步

select min(salary)
from employees
group by department_id
having min(salary) > (
	select min(salary)
	from employees
	where department_id = 50
);

7.2.2 列子查询(多行子查询)

  • 返回多行
  • 使用多行比较符
  • 也可以把in替换成 =any not in 替换为<> all
操作符 含义
in/not in 等于列表中的任意一个,用的比较多
any / some 和子查询返回的某一个值比较,可以用min/max代替
all 和子查询返回的所有值比较,可以用max/max代替

案例1:返回location_id是1400或1700的部门的所有员工姓名
第一步:查询部门location_id 为1400 或 1700的部门

# 一列多行
select distinct department_id 
from departments
where location_id in (1400,1700);

第二步:查询员工姓名,要求部门号是第一步中的某一个

select last_name
from employees
where department_id in (  # 也可以把in替换成 =any   not in 替换为<> all
	select distinct department_id 
	from departments
	where location_id in (1400,1700)
);

案例2:返回其他工种中比 IT_PROG 工种任意工资低的 员工的员工号,姓名,job_id,salay
使用ANY
第一步:查询IT_PROG 工种的工资

select salary
from employees
where job_id = 'IT_PROG';

第二步:查询工资比 IT_PROG 工种的任意工资 低的员工的相关信息

select employee_id,last_name,job_id,salary
from employees
where salary < any(
	select salary
	from employees
	where job_id = 'IT_PROG'
) and job_id <> 'IT_PROG';

用max代替,相当于标量子查询

select employee_id,last_name,job_id,salary
from employees
where salary < (
	select max(salary)
	from employees
	where job_id = 'IT_PROG'
) and job_id <> 'IT_PROG';

7.2.3 行子查询(一行多列)

此情况用的比较少
案例:查询员工编号最小并且工资最高的员工信息

select *
from employees
where (employee_id,salary) = (
	select min(employee_id),max(salary)
	from employees
);

7.3 select后面的子查询

仅仅支持标量子查询

案例:查询每个部门的员工个数

select d.*,(
	select count(*)
	from employees e
	where e.department_id = d.department_id
) 个数
from departments d;

员工个数为0的部门也能求出来,如果使用group by 只能求出员工个数不为0的部门

7.4 from后面的子查询

将子查询结果充当一张表,要求必须起别名,否则找不到

案例:查询每个部门的平均工资的工资等级

第一步:查询每个部门的平均工资

select department_id,avg(salary)
from employees
group by department_id;

第二步:连接第一步结果和job_grades表,筛选条件:平均工资 between lowest_sal and highest_sal

select avg_dep.*,grade_level
from (
	select department_id,avg(salary) as avg
	from employees
	group by department_id
) avg_dep
inner join job_grades g
on avg_dep.avg between lowest_sal and highest_sal;

7.5 exists 后面(相关子查询)

语法:

select exists(完整的查询语句);
  • 结果:1或0,查看子查询语句是否有数据

案例:查询有员工的部门名

select department_name
from departments d
where exists(
	select *
	from employees e
	where d.department_id = e.department_id
);

使用in,not in 为没有员工的部门名

select department_name
from departments d
where department_id in(
	select department_id
	from employees
);

7.6 案例

案例1:查询各部门中工资比本部门平均工资高的员工的员工号,姓名,工资,部门
第一步:查询本部门的平均工资

select avg(salary) as ag,department_id
from employees e
 group by department_id;

第二步:连接第一步结果集和employees表,进行1筛选

select employee_id,last_name,salary,e.department_id
from employees e
inner join (
	select avg(salary) as ag,department_id
	from employees e
	group by department_id
) as ag_dep
on e.department_id = ag_dep.department_id
where salary > ag_dep.ag;

案例2:查询 和 姓名中包含字母u的员工 在同一部门的员工的员工号和姓名
第一步:查询姓名中包含字母u的员工所在的部门

# 去重
select distinct department_id
from employees
where last_name like '%u%';

第二步:查询部门号等于第一步中任意一个的员工号和姓名,并去除名字中带u的

select employee_id,last_name
from employees
where department_id in (
	select distinct department_id
	from employees
	where last_name like '%u%'
) and last_name not like '%u%';

案例3:查询部门 在location_id为1700的 部门 工作的员工的员工号
第一步:查询location_id为1700的部门

select distinct department_id
from departments
where location_id = 1700;

第二步:筛选

select employee_id 
from employees e
where e.department_id in (  # in 也可以写成 =any
	select distinct department_id
	from departments
	where location_id = 1700
);

8. 分页查询

8.1 语法

select 查询列表
from[join type join2]
[on 连接条件]
[where 筛选条件]
[group by 分组字段]
[having 分组后筛选]
[order by 排序字段]
limit offset,size;
/* 
offset:要显示条目的起始索引(从0开始)
size:要显示的条目个数

要显示的页数:page ,每页显示的条目个数size
limit (page-1)*size,size
*/

8.2 案例

案例1:查询前5条员工信息

# 0可以省略
select * from employees limit 0,5;

案例2:有奖金的员工信息,并显示工资前10名

select *
from employees
where commission_pct is not null
order by salary desc
limit 0,10;

9. 联合查询

  • 应用场景:

    • 要查询的结果来自于多张表,且多个表没有直接的连接关系,但查询信息一致时使用
  • 作用

    • 将多条查询语句的结果合并为一个结果
  • 语法:

    查询语句1
    union
    查询语句2
    ...
    

案例:查询部门编号 > 90或邮箱包含a的员工信息

# 联合查询
select * from employees where department_id > 90 
union 
select * from employees where email like '%a%';

10. 各语句执行顺序

每执行一步都会生成一个虚拟的表格

语句 执行顺序
select 查询列表 7
from 表 1
join type join 表2 2
on 连接条件 3
where 筛选条件 4
group by 分组字段 5
having 分组后筛选 6
order by 排序字段 8
limit offset,size 9

三、DML(Data Manipulate Language)数据操作语言

1. 插入语句

# 方式一
insert into 表名(列名,...) 
values(1,...),
(2,...)
...;

注意

  • 插入的值的类型要与列的类型一致或兼容(可以隐式转换)
  • 值可以为空的列的填写方式
    • 列写,值用NULL
    • 列与值都不写
  • 列的顺序可以调换,但是需要保证插入的值与列一致
  • 可以省略列名,默认为所有列,且列的顺序与表中一致
# 方式二
insert into 表名
set 列名1 =1,列名2 =2...;

两种方式比较

  • 方式一支持多行插入,方式二不支持
  • 方式一支持子查询,方式二不支持
insert into table1(...)
select ... ;
# 相当于把select子查询得到的结果集插入到对应列

2. 修改语句

2.1 修改单表的记录

语法

update 表名
set 列名1 = 新值1,列名2 = 新值2...
where 筛选条件;
  • 不加筛选条件则修改所有表
  • 客户端启动时可加上参数:mysql -u root --safe-updates -p 如果数据更新不加where会报错

2.2 修改多表的记录

语法

# sql92 只支持内联
update table1 别名,table2 别名
set1 =1,...
where 连接条件
and 筛选条件;
# sql99
update table1 别名
inner|left|right join table2 别名
on 连接条件
set1 =1,...
where 筛选条件;

3. 删除语句delete命令

3.1 单表删除

# 方式一
delete from 表名 [where 条件];
  • 不加条件会删除表中所有数据
  • truncate命令
# 方式二
truncate table 表名;
  • 清空表中所有记录,相当于delete from 表名;

3.2 多表删除

# sql92 
delete 删除表的别名
from table1 别名,table2 别名
where 连接条件
and 筛选条件;
/*
别名可以不起
删除哪个表的记录就在delete 后写哪个
*/
# sql99 
delete 删除表的别名
from table1 别名
inner|left|right join table2 别名
on 连接条件
where 筛选条件;
/*

3.3 delete 与 truncate 区别

  • delete 可以加where条件,truncate不能加
  • truncate删除,效率高一点
  • 如果要删除的表中有自增长列,delete删除之后再插入数据,自增长列的值从断点开始;而truncate删除后,自增长列从1开始
  • truncate删除没有返回值,delete有返回值
  • truncate删除不能回滚,delete删除可以回滚
  • truncate table 表名 不会写入日志,直接删除,delete from 表名,会有日志。

四、DDL(Data Define Languge)数据定义语言

1. 数据库的管理

1.1 创建库

create database 数据库名;
# 容错性处理,如果库不存在就创建,存在也不会报错
create database if not exists 数据库名;

1.2 修改库

# 更改数据库的字符集
alter database 数据库名 character set gbk;

1.3 删除库

drop database 数据库名;
# 容错性处理
drop database if exists 数据库名; 

2. 表的管理

2.1 创建表

create table 表名(
	列名1 列的类型 [(长度) 约束],
	列名2 列的类型 [(长度) 约束],
	...
	列名n 列的类型 [(长度) 约束]
);

案例:

create table student(
	id int auto_increment,
	name varchar(64) not null,
	primary key(id)
	)engine = InnoDB default charset = utf8;
  • 字段可以设置为不为空,即not null;
  • auto_increment 定义列为自增的属性,一般用于主键,数值会自动加1;
  • primary key 关键字用于定义列为主键。 可以使用多列来定义主键,列间以逗号分隔。
  • engine 设置存储引擎,charset 设置编码。此句可不写
    在这里插入图片描述

2.2 修改表

语法:

alter table 表名 add|drop|modify|change 列名 [列类型 约束];
  • 修改字段名

    alter table 表名 change column 原字段 新字段 新字段属性;
    #column 可以省略
    
  • 修改字段属性

    alter table 表名 modify 字段 字段属性;
    
  • 增加字段

    alter table 表名 add 字段 字段属性 (after 字段);
    
  • 删除字段

    alter table 表名 drop 字段;
    
  • 重命名表名

    alter table 原表名 rename 新表名;
    

2.3 删除表

drop table 表名;
drop table if exists 表名;

2.4 复制表

复制表结构

  • 复制表的所有结构
    create table 新表 like1
    
  • 复制部分结果,不复制数据
    create table 新表
    select 想要复制的字段
    from1
    where 0;
    

复制表结构与数据

  • 复制全部数据
    create table 新表 select * from1;
    # 部分数据需要加条件
    
  • 复制部分数据
    create table 新表 
    select 需要的字段 
    from1
    where 筛选条件
    

3. MySQL基础数据类型

3.1 数字型

原则:所选择的类型越简单越好,能保存数值的类型越小越好

类型 大小 范围(有符号) 范围(无符号) 用途
tinyint 1字节 -128-+127 0-255 最小整数
int 4字节 -2147483648-+2147483647 大整数值
float(m,n) 4-8个字节 单精度浮点型(浮点数)
double(m,n) 8个字节 双精度浮点型(浮点数)
decimal(m,n) 变长 浮点数(更加精确,长度一般无限制)

3.2 字符型

类型 大小 用途
char(M) 0-255字节 存储定长的字符串,M默认为1;耗费空间但效率高
varchar(M) 0-65535字节 存储变长的字符串,无默认值;节省空间但效率低
text 0-65535字节 长文本数据
blob 0-65535字节 二进制文本(不建议)
enum(‘w’,‘m’) 65535个成员 枚举
set(‘w’,‘m’) 64个成员 集合

3.3 时间型

类型 大小 范围 格式 用途
date 3字节 1000-01-01/9999-12-31 YYYY-MM-DD 日期值
time 3字节 -838:59:59/838:59:59 HH:MM:SS 时间值
year 4字节 1901/2155 YYYY 年份值
datetime 8字节 1000-01-01 00:00:00 / 9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 混合时间和日期
timestamp 4字节 1970-2038年的某个时刻 日期+时间
  • timestamp支持的时间范围较小
  • timestamp与实际时区有关,更能反应实际的日期,而datetime只能反映出插入时的当地时区
  • timestamp的属性受MySQL版本和SQLMode的影响很大

显示当前时区

show variables like 'time_zone';

设置时区

set time_zone='+9:00';# 东9区

4. 常见约束

对表中的数据进行限制,来保证表中的数据准确可靠

create table 表名(
	字段名 字段类型 列级约束,
	
	字段名 字段类型,
	表级约束
);

4.1 六大约束

约束 说明
not null 非空,用于保证该字段的值不能为空
default 默认,保证该字段有默认值
primary key 主键,保证该字段值的唯一性,且不为空
unique 唯一,保证该字段的唯一性,可以为空,但只能有一个
check 检查约束(MySQL不支持)
foreign key 外键,用于限制两个表的关系,用于保证该字段的值必须来自主表的关联列的值,在从表添加外键约束,用于引用主表在某列的值

4.2 添加时机与分类

添加约束的时机

  • 创建表
  • 修改表

约束的添加分类:

  • 列级约束:六大约束语法上都支持,但外键约束没有效果
    • 直接在字段名和类型后面追加约束类型
    • 不可以起约束名
  • 表级约束:六大约束除了非空、默认都可以
    • 在字段的最下面
    • [constraint 约束名] 约束类型(字段名)
    • 可以起约束名

4.2.1 创建表时添加约束

4.2.1.1 添加列级约束
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 references major(id)                  # 外键(不起作用)
	
);

create table major(
	id int primary key,
	majorName varchar(20)
);

#查看表中的索引
show index from 表名;
4.2.1.2 添加表级约束
create table stuinfo(
	id int,
	stuName varchar(20),
	gender char(1),
	seat int,
	age int,
	majorId int, 
	# 表级约束,不支持默认与非空
	constraint pk primary key(id), #主键
	unique(seat)# 唯一
	foreign key(majorId) references major(id) # 外键
);

4.2.2 修改表时添加约束

添加列级约束。可添加项:默认,非空

alter table 表名 modify 字段 字段属性 约束;

添加表级约束。可添加项:主键,唯一,外键

alter table 表名 add 约束(字段) [外键的引用];

4.2.3 修改表时删除约束

删除非空约束

alter table 表名 modify 字段 字段属性 null;

删除默认约束

alter table 表名 modify 字段 字段属性;

删除主键

alter table 表名 drop primary key;

删除唯一

alter table 表名 drop union index 字段;

删除外键

alter table 表名 drop foreign key 外键名;

4.3 主键与唯一的区别

区别 主键 唯一
是否唯一
是否可以为空 是,但只能有一个非空
个数 一个 可以多个
是否允许组合(不推荐) 是(联合主键)

4.4 外键的特点

  • 要求在从表设置外键关系
  • 从表的外键列的类型和主表的关联列的类型要求一致或者兼容,名称无要求
  • 主表的关联列必须是一个key(一般是主键或者唯一)
  • 插入数据时,先插入主表,再插入从表;删除数据时,先删除从表,再删除主表

5. 标识列

标识列也称为自增长列:可以不用手动的插入值,系统提供默认的序列值;关键字: auto_increment

  • 必须与key进行搭配,一般和主键搭配,唯一也可以
  • auto_increment 的步长可以设置
  • 最多有一个标识列

5.1 创建表时设置标识列

auto_increment 定义列为自增的属性,一般用于主键,数值会自动加1;

create table student(
	id int primary key auto_increment,
	name varchar(64) not null
	);

5.2 修改表时设置标识列

alter table 表名 modify 字段名 int primary key auto_increment;

5.3 修改表时删除标识列

alter table 表名 modify 字段名 int primary key;

5.4 设置步长及起始值

执行下面语句

show variables like '%auto_increment%';

在这里插入图片描述
其中auto_increment_increment 为步长可以设置

set auto_increment_increment = 3;# 步长设置为3

       auto_increment_increment 为起始值,MySQL中不支持设置,设置没有效果;可以在想修改起始值的地方手动插入,比如表的第一行插入为10,之后的数据都会在10的基础上进行自增长

五、TCL(Transaction Control Language)事务控制语言

       事务是由单独单元的一个或多个SQL语句组成,在这个单元中,每个MySQL语句是相互依赖的。而整个单独单元作为一个不可分割的整体,如果单元中某条SQL语句一旦执行失败或产生错误,整个单元将会回滚。所有受到影响的数据将返回到事务开始以前的状态,如果单元中的所有SQL语句均执行成功,则事务被顺利执行

1. 存储引擎了解

  • 在MySQL中的数据用各种不同的技术存储在文件(或内存)中。

  • 查看MySQL支持的存储引擎

    show engines;
    

    在这里插入图片描述

  • MySQL中用的最多的存储引擎有:innodb,MyISAM,MEMORY等,其中innodb支持事务;MyISAM,MEMORY等不支持事务

2. 事务的ACID特性

  • 原子性(Atomicity)
    • 是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生;
  • 一致性(Consistency)
    • 事务必须使数据库从一个一致性状态变换到另一个一致性状态。
  • 隔离性(Isolation)
    • 事务的隔离性是指一个事务的执行不能够被其他事务打扰。即一个事务内部的操作及使用的数据对并发的其他事务时隔离的,并发执行的各个事务之间不能相互干扰。
  • 持久性(Durability)
    • 持久性是指一个事务一旦被提交,则会永久的改变数据库的数据,接下来的其他操作和数据库故障不应该对其有任何影响。

3. 事务的创建

3.1 分类

分类

  • 隐式事务:事务没有明显的开启和结束的标记
    • 比如insert,update,delete语句
  • 显式事务:事务具有明显的开启和结束的标记
    • 前提:必须先设置自动提交功能为禁用
# 自动提交功能,默认开启
show variables like 'autocommit';

# 关闭自动提交功能,只针对当前会话有效
set autocommit = 0;

在这里插入图片描述

3.2 创建步骤

步骤1:开启事务

set autocommit = 0;
start transaction;可选

步骤2:编写一组事务的SQL语句(增删改查:select insert update delete)而DDL语言没有事务之说

SQL语句1savepoint a;
# 可选,设置保持点。a为节点名
# 搭配rollback使用,若回滚到保持点a,则会恢复保持点a以下的语句

SQL语句2...

步骤3:结束事务

commit; # 成功时执行  提交事务

rollback;# 出错时执行 回滚事务,得联合应用程序

rollback to a;# 回滚到保持点a

4. 数据库的隔离级别

4.1 并发问题

       对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:

  • 脏读:对于两个事务T1,T2,T1读取了已经被T2更新但还没有被提交的字段。之后,若T2回滚,T1读取的内容就是临时且无效的
  • 不可重复读:对于两个事务T1,T2,T1读取了一个字段,然后T2更新了该字段。之后,T1再次读取同一个字段,值就不同了
  • 幻读:对于两个事务T1,T2,T1读取了一个字段,然后T2在该表中插入了一些新的行。之后,T1再次读取同一个表,就会多出几行。

4.2 数据库事务的隔离级别

       数据库事务的隔离性:数据库系统必须具有隔离并发运行各事务的能力,使他们不会相互影响,避免各种并发问题。
       一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。

隔离级别 描述
READ UNCOMMITTED(读未提交数据) 允许事务读取未被其他事务提交的变更。脏读、不可重复读、幻读的问题都会出现
READ COMMITED(读已提交数据) 只允许事务读取已经被其他事务提交的变更。可以 避免脏读,但不可重复读和幻读问题仍可能存在
REPEATABLE READ(可重复读) 确保事务可以多次从一个字段中读取相同的值。在这个事务持续期间,禁止其他事务对这个字段进行更新。可以避免脏读和不可重复读,但幻读问题仍会出现
SERIALIZABLE(串行化) 确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作。所有并发问题都可以避免,但性能十分低下
  • Oracle 支持2种事务隔离级别:READ COMMITED,SERIALIZABLE。Orcale默认的事务隔离级别为READ COMMITED
  • MySQL支持4种事务隔离级别。默认为REPEATABLE READ

查看默认事务隔离级别

select @@tx_isolation;
# 或  8.0版本以上
select @@transaction_isolation;

设置当前隔离级别

set session transaction isolation level 隔离级别;

设置全局隔离级别

set global session transaction isolation level 隔离级别;

六、视图

1. 概述

1.1 含义

MySQL5.0.1 版本出现的新特性。一种虚拟存在的表,行和列的数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的,只保存了SQL逻辑,不保存查询结果。

1.2 应用场景

  • 多个地方用到同样的查询结果
  • 该查询结果使用的SQL语句较复杂

1.3 视图好处

  • 重用SQL语句
  • 简化复杂的SQL操作,不必知道查询细节
  • 保护数据,提高安全性

2. 创建视图

2.1 语法

create view 视图名
as
查询语句;

2.2 案例

案例1:查询姓名中包含a字符的员工名,部门名和工种信息

# 创建视图 myv1
create view myv1
as

select last_name,department_name,job_title
from employees e

inner join departments d on e.department_id = d.department_id
inner join jobs j on j.job_id = e.job_id;

# 使用视图
select * from myv1 where last_name like '%a%';

3. 修改视图

方式一
如果视图存在就进行修改,不存在则创建

create or replace 视图名
as 
查询语句;

方式二
使用关键字alter

alter view 视图名
as
查询语句;

4. 删除视图

drop view 视图名1,视图名2,...;

5. 查看视图结构

desc 视图名; # 视图结构
show create view 视图名;# 查看建表语句

6. 视图数据更新

对视图的更改会作用到原表,一般会对视图进行权限限制

6.1 插入数据

insert into 视图名(列名,...) 
values(1,...),
(2,...) 
...;

插入的数据会直接作用到原表,有些视图数据不能够进行插入

6.2 修改数据

update 视图名
set 列名1 = 新值1,列名2 = 新值2...
where 筛选条件;

6.3 删除数据

delete from 表名 where 条件;

6.4 不允许更新视图的情况

  • 包含以下关键字的SQL语句:分组函数,distinct,group by ,having,union,union all
  • 常量视图
  • select中包含子查询
  • join
  • from一个不能更新的视图(视图可以嵌套)
  • where 子句的子查询引用了from子句中的表

7. 视图与表的对比

xx 创建语法的关键字 是否实际占用了物理空间 使用
视图 create view 保存了SQL逻辑 增删改查,一般不能增删改
create table 保存了数据和逻辑 增删改查

七、变量

1. 分类

  • 系统变量
    • 全局变量:global
    • 会话变量:session
  • 自定义变量
    • 用户变量
    • 局部变量

2. 系统变量

  • 变量由系统提供,属于服务器层面。
  • 默认为session,可写可不写。
  • 服务器每次启动将为所有的全局变量赋初值,针对于所有的会话(连接)有效,但是不能跨重启(每次启动会恢复到系统配置的默认值)。
  • 会话变量针对于当前对话(连接)有效

查看所有系统变量

show global | [session] variables;

查看满足条件的部分系统变量

show global | [session] variables like '%char%';

查看指定的某个系统变量的值

select @@global | [session] .系统变量名;

为某个系统变量赋值

# 语法1
set global | [session] 系统变量名 =;
# 语法2 
set @@global | [session] .系统变量名 =;

3. 自定义变量

  • 由用户自己定义
  • 使用步骤:声明,赋值,使用(查看,比较,运算等)

3.1 用户变量

  • 作用域:针对当前会话(连接)有效
  • 可以放在任何地方,begin end 内部或者外部

声明并初始化

set @用户变量名 =;
set @用户变量名 :=; # 推荐
select @用户变量名=;

赋值(更新用户变量的值)

# 方式一:利用声明并初始化操作
	set @用户变量名 =;
	set @用户变量名 :=;
	select @用户变量名=;
# 方式二:通过select into,把表中数据复制给变量
	select 字段1,字段2 ... into @变量名1, @变量名2 ...
	from 表名; 

使用(查看用户变量的值)

select @用户变量名;

案例:使用用户变量

set @m = 1;
set @n = 2;
set @sum = @m + @n;
select @sum;

3.2 局部变量

  • 仅仅在定义它的begin end中有效
  • 应用于begin end中的第一句话

声明

declare 局部变量名 类型;
declare 局部变量名 类型 default;

赋值

# 方式一:通过set或select 
	set 局部变量名 =;
	set 局部变量名 :=;
	select @局部变量名=;
# 方式二:通过select into
	select 字段1,字段2... into 局部变量名1,局部变量名2...
	from 表名; 

使用

select 局部变量名;

八、存储过程和函数

1. 存储过程

1.1 含义

一组预先编译好的SQL语句的集合,理解为批处理语句

  • 提高代码的复用性
  • 简化操作
  • 减少编译次数并且减少了和数据库服务器的连接次数,提高了效率

1.2 创建

语法:

create procedure 存储过程名(参数列表)
begin
	存储过程体(一组合法的SQL语句)
end

注意

  • 参数列表由三部分组成:参数模式 参数名 参数类型

    # 举例
    in stuName varchar(20)
    
参数模式 说明
in 作为输入,该参数需要调用方传入值
out 作为输出,该参数可以作为返回值
inout 可以作为输入或输出,既可以作为传入值,也可以作为返回值
  • 存储过程体
    • 如果存储过程体仅有一句话,begin end 可以省略
    • 存储过程体中的每条SQL语句的结尾必须加分号
    • 存储过程的结尾可以使用delimiter 重新设置
      • 语法: delimiter 结束标记

1.3 调用

语法:

call 存储过程名(实参列表);

1.4 删除存储过程

  • 一次只能删除一个,不能一次删除多个
  • 不能修改,只能删除后重新创建
drop procedure 存储过程名;

1.5 查看存储过程信息

不能使用desc 存储过程名。

show create procedure 存储过程名;

1.6 案例

1.4.1 空参列表

案例1:插入到account表中5条记录

步骤1:创建存储过程myp1,并把结束标记改为$

delimiter $
create procedure myp1()
begin
	insert into account(username,money) 
	values('employee1','2000'),
	('employee2','3000'),
	('employee3','4000'),
	('employee4','5000'),
	('employee5','6000');
end $

步骤2:调用存储过程体myp1

call myp1()$

步骤3:查看account表中的记录

select * from account$ 

1.6.2 创建带in模式参数的存储过程

案例1:(单变量输入)根据女生名 查询 其对应的男朋友信息(数据库文件:girl.sql)

步骤1:创建存储过程myp1,并把结束标记改为$

delimiter $
create procedure myp1(in beautyName varchar(20))
begin 
	select bo.*
	from boys bo
	right join beauty b on bo.id = b.boyfriend_id
	where b.name = beautyName;
end $

步骤2:调用存储过程体myp1

call myp1('赵敏')$

在这里插入图片描述

案例2:(多变量输入)查看account表中员工名与他的钱是否一致

delimiter $ 
create procedure myp2(in username varchar(20),in money varchar(10))
begin 
	declare res int default 0;# 声明并初始化
	
	select count(*) into res # 给变量赋值
	from account
	where account.username = username
	and account.money = money;
	# 使用,如果得到res 为0说明没有匹配不上,如果res > 0说明正确
	select if(res,'正确','错误');
end $

调用

call myp2('boss','1000');

1.6.3 创建带out模式的存储过程

案例1:根据女神名返回对应其男朋友姓名

delimiter $
create procedure myp2(in beautyName varchar(20),out boyName varchar(20)) # 自动返回boyName
begin
	select bo.boyName into boyName #赋值给boyName
	from boys bo
	inner join beauty b 
	on b.boyfriend_id = bo.id
	where b.name = beautyName;
end $

调用

# 定义一个用户变量接收返回值
set @bName$
call myp2('赵敏',@bName)$
select @bName$

1.6.4 创建带inout模式的存储过程

案例:传入a,b两个数,返回他们的2倍

delimiter $
create procedure myp3(inout a int,inout b,int)
begin 
	set a = 2 * a;
	set b = 2 * b;
end $

调用

# 创建两个用户变量
set @m = 10$
set @n = 20$
call myp3(@m,@n)$
select @m,@n$

2. 函数

2.1 函数与存储过程的区别

  • 函数只能有一个返回:适合处理数据后返回一个结果
  • 存储过程可以有0个或多个:批量插入、批量更新;适合增删改

2.2 创建函数

语法:

create function 函数名(参数列表) returns 返回类型
begin 
	函数体
	return;
end 
  • 参数列表包含两部分:参数名 参数类型
  • 肯定有return语句,没有会报错
  • 如果return语句没有放在函数体最后也不报错,但是不建议
  • 函数体中仅有一句话可以省略begin end
  • 可以使用delimiter语句设置结束标记

2.3 调用函数

select 函数名(实参列表)

2.4 查看函数

show create function 函数名;

2.5 删除函数

drop function 函数名;

2.6 案例

2.6.1 无参有返回

案例:返回公司的员工个数

delimiter $
create function myf1() returns int
begin
	declare c int default 0; #定义局部变量作为返回值
	
	select count(*) into c   # 为变量赋值
	from employees;

	return c;
end $

调用

select myf1()$

2.6.2 有参有返回

案例:根据员工名返回工资

delimiter $
create function myf2(eName varchar(20)) returns double
begin 
	declare money double default 0;# 定义局部变量
	# set @money := 0; #定义用户变量,使用时变量名前需要加 @ 
	
	select salary into money
	from employees
	where last_name = eName;
	
	return money;
end $

调用

select myf2('Baer')$

3. 查看MySQL中的存储过程和函数

用户创建的存储过程和函数可以在mysql.sql中的proc表中查看

 select db,name,type from mysql.proc;

在这里插入图片描述

九、流程控制结构

  • 顺序结构:程序从上往下执行
  • 分支结构:程序从两条或多条路径中选择一条去执行
  • 循环结构:程序在满足一定条件的基础上,重复执行一段代码

1. 分支结构

1.1 if函数

  • 语法
    if(表达式1,表达式2,表达式3);
    
  • 执行顺序
    • 如果表达式1成立,返回表达式2的值,否则返回表达式3的值

1.2 case结构

(一) 相当于switch case,实现等值判断

case 要判断的字段或表达式  
when 常量1  then  要显示的值1或语句1;
when 常量2  then  要显示的值2或语句2;
......
else 要显示的值n或语句n;
end;#返回的是值
end case;# 返回的是语句

(二)相当于多重if,实现区间判断

case 
when 条件1 then 要显示的值1或语句1;
when 条件1 then 要显示的值1或语句1;
......
else 要显示的值n或语句n;
end;#返回的是值
end case;# 返回的是语句

特点:

  • 可以作为表达式,嵌套在其他语句中使用,可以放在任何地方,begin end中或之外
  • 可以作为独立的语句使用,只能放在begin end 中
  • when中的值或条件成立,则执行对应then后面的语句,并结束case;都不满足则执行else中的语句或值
  • else语句可以省略,如果省略了else并且when中其他条件都不满足,则返回NULL

案例:创建存储过程,根据传入的成绩来显示等级;90-100:显示A ;80-90:显示B;60-80:显示C;其他:显示D

delimiter $
create procedure test_case(in score int)
begin 
	# 区间判断
	case 
	when score >= 90 and score <= 100 then select 'A';
	when score >= 80 then select 'B';
	when score >= 60 then select 'C';
	else select 'D';
	end case;  # 执行的是语句,所以使用end case
end $

调用

call test_case(99)$

1.3 if结构

语法:(只能在begin end中使用)

if 条件1 then 语句1;
elseif 条件2 then 语句2;
elseif 条件3 then 语句3;
...
[else 语句n;]
end if;

案例:创建函数,根据传入的成绩来显示等级;90-100:返回A ;80-90:返回B;60-80:返回C;其他:返回D

delimiter $
create function test_if(score int) returns char
begin
	if score >= 90 and score <= 100 then return 'A';
	elseif score >= 80 then return 'B';
	elseif score >= 60 then return 'C';
	else return 'D';
	end if;
end $

调用

select test_if(55)$

2. 循环结构

分类:while,loop,repeat
循环控制

  • iterate:类似于continue ,继续,结束本次循环,继续下一次
  • leave:类似于break,跳出,结束当前所在循环

2.1 while

语法:

[标签:] while 循环条件 do
	循环体;
end while [标签];

案例:批量插入,根据次数插入到account 表中多条记录

create procedure pro_while(in insertCount int)
begin
	declare i int default 1; #定义循环因子
	while i <= insertCount do
		insert into account(username,money) values(concat('employee',i),'10000');
		set i = i + 1;
	end while;
end $

调用

call pro_while(100)$

案例:批量插入,根据次数插入到account 表中多条记录
使用leave ,当次数大于20时停止,此时需要添加标签

create procedure pro_while(in insertCount int)
begin
	declare i int default 1; #定义循环因子
	a:while i <= insertCount do
		insert into account(username,money) values(concat('boss',i),'10000');
		
		if i >= 20 then leave a;
		end if;
		
		set i = i + 1;
	end while a;
end $

案例:批量插入,根据次数插入到account 表中多条记录
使用iterate ,当次数大于20时停止,此时需要添加标签

create procedure pro_while(in insertCount int)
begin
	declare i int default 0; #定义循环因子
	a:while i <= insertCount do
		set i = i + 1;
		if mod(i,2) != 0 then iterate a;
		end if;
		insert into account(username,money) values(concat('manager',i),'10000');		
	end while a;
end $

2.2 loop

语法:

[标签:] loop
	循环体;
end loop [标签];

没有循环条件,可以用来模拟简单的死循环

2.3 repeat

语法:类似于do…while

[标签:] repeat
	循环体;
untile 循环结束条件
end repeat [标签];

参考

猜你喜欢

转载自blog.csdn.net/weixin_44515978/article/details/121195939