MySQL 数据库
数据库的好处
-
持久化数据到本地
-
可以实现结构化查询,方便管理
数据库相关概念
-
DB:数据库,保存一组有组织的数据的容器
-
DBMS:数据库管理系统,又称为数据库软件(产品),用于管理 DB 中的数据
-
SQL:结构化查询语言,用于和 DBMS 通信的语言
数据库存储数据的特点
-
将数据放到表中,表再放到库中
-
一个数据库中可以有多个表,每个表都有一个的名字,用来标识自己。表名具有唯一性。
-
表具有一些特性,这些特性定义了数据在表中如何存储,类似 java 中 “类”的设计。
-
表由列组成,我们也称为字段。所有表都是由一个或多个列组成的,每一列类似 java 中的”属性”
-
表中的数据是按行存储的,每一行类似于 java 中的“对象”。
MySQL 产品的介绍和安装
MySQL 服务的启动和停止
方式一:计算机——右击管理——服务
方式二:通过管理员身份运行
net start 服务名(启动服务)
net stop 服务名(停止服务)
MySQL 服务的登录和退出
方式一:通过mysql自带的客户端
只限于root用户
方式二:通过windows自带的客户端
登录:
mysql 【-h主机名 -P端口号 】-u用户名 -p密码
退出:
exit或ctrl+C
MySQL 的常见命令
# 查看当前所有的数据库
show databases;
# 打开指定的库
use 库名
# 查看当前库的所有表
show tables;
# 查看其它库的所有表
show tables from 库名;
# 创建表
create table 表名(
列名 列类型,
列名 列类型,
。。。
);
# 查看表结构
desc 表名;
# 查看服务器的版本
# 方式一:登录到mysql服务端
select version();
# 方式二:没有登录到mysql服务端
mysql --version
# 或
mysql --V
MySQL 的语法规范
-
不区分大小写,但建议关键字大写,表名、列名小写
-
每条命令最好用分号结尾
-
每条命令根据需要,可以进行缩进 或换行
-
注释
单行注释:#注释文字
单行注释:– 注释文字
多行注释:/* 注释文字 */
SQL 的语言分类
DQL(Data Query Language):数据查询语言
select
DML(Data Manipulate Language):数据操作语言
insert 、update、delete
DDL(Data Define Languge):数据定义语言
create、drop、alter
TCL(Transaction Control Language):事务控制语言
commit、rollback
SQL 的常见命令
# 查看所有的数据库
show databases;
# 打开指定 的库
use 库名;
# 显示库中的所有表
show tables;
# 显示指定库中的所有表
show tables from 库名;
# 创建表
create table 表名(
字段名 字段类型,
字段名 字段类型
);
# 查看指定表的结构
desc 表名;
# 显示表中的所有数据
select * from 表名;
DQL 语句
进阶 1:基础查询
语法:
SELECT 要查询的东西
FROM 表名;
类似于 Java 中 :System.out.println(要打印的东西);
特点:
-
通过 select 查询完的结果 ,是一个虚拟的表格,不是真实存在
-
要查询的东西 可以是常量值、可以是表达式、可以是字段、可以是函数
起别名
select last_name as 姓;
select last_name 姓;
去重
select distinct department_id from employees;
+号的作用
# 两者都为数值型,则做加法运算
select 100+90;
# 一个是字符型,一个是数值型,将字符型转换为数值型做加法运算
select '100'+90;
# 一个是字符型,一个是数值型,将字符型转换为数值型做加法运算,转换失败则置为零
select 'jhon'+10;
# 一方为null,则结果肯定为null
select null+10;
进阶 2:条件查询
条件查询:根据条件过滤原始表的数据,查询到想要的数据
语法:
select
要查询的字段|表达式|常量值|函数
from
表
where
条件;
分类:
一、条件表达式
示例:salary>10000
条件运算符:
“> < >= <= = != <>
二、逻辑表达式
示例:salary>10000 && salary<20000
逻辑运算符:
and(&&):两个条件如果同时成立,结果为 true,否则为 false or(||):两个条件只要有一个成立,结果为 true,否则为 false not(!):如果条件成立,则 not 后为 false,否则为 true
三、模糊查询
示例:last_name like ‘_a%’
like、between and、in、is null
进阶 3:排序查询
语法:
select
要查询的东西
from
表
where
条件
order by 排序的字段|表达式|函数|别名 【asc|desc】
进阶 4:常见函数
一、单行函数
-
字符函数
concat 拼接
substr 截取子串
upper 转换成大写
lower 转换成小写
trim 去前后指定的空格和字符
ltrim 去左边空格
rtrim 去右边空格
replace 替换
lpad 左填充
rpad 右填充
instr 返回子串第一次出现的索引
length 获取字节个数
-
数学函数
round 四舍五入
rand 随机数
floor 向下取整
ceil 向上取整
mod 取余
truncate 截断
-
日期函数
now 当前系统日期+时间
curdate 当前系统日期
curtime 当前系统时间
str_to_date 将字符转换成日期
date_format 将日期转换成字符
-
流程控制函数
if 处理双分支
case 语句 处理多分支,情况 1:处理等值判断,情况 2:处理条件判断
-
其他函数
version 版本
database 当前库
user 当前连接用户
二、分组函数
sum 求和
max 最大值
min 最小值
avg 平均值
count 计数
特点:
-
以上五个分组函数都忽略 null 值,除了 count(*)
-
sum 和 avg 一般用于处理数值型 max、min、count 可以处理任何数据类型
-
都可以搭配 distinct 使用,用于统计去重后的结果
-
count 的参数可以支持: 字段、、常量值,一般放 1 建议使用 count()
进阶 5:分组查询
语法:
select 查询的字段,分组函数
from 表
group by 分组的字段
特点:
-
可以按单个字段分组
-
和分组函数一同查询的字段最好是分组后的字段
-
分组筛选
针对的表 位置 关键字 分组前筛选 原始表 group by 的前面 where 分组后筛选 分组后的结果集 group by 的后面 having -
可以按多个字段分组,字段之间用逗号隔开
-
可以支持排序
-
having 后可以支持别名
-
分组函数做条件肯定放在 having 子句中
-
能用分组前筛选的,就优先使用分组前筛选
进阶 6:多表连接查询
笛卡尔乘积:如果连接条件省略或无效则会出现
解决办法:添加上连接条件
一、分类
按年代分类:
-
sql192 标准:内连接
-
sql199 标准【推荐】:内连接+外链接(左外、右外)+交叉连接
按功能分类
-
内连接
等值连接、非等值连接、自连接
-
外连接
左外连接、右外连接、全外连接
-
交叉连接
二、sql192 标准
# 等值连接
select 表1.字段1, 表2.字段2
from 表1,表2
where 表1.字段3 = 表2.字段4
# 非等值连接
类比等值连接
# 自连接
SELECT e.last_name,m.last_name
FROM employees e,employees m
WHERE e.`manager_id`=m.`employee_id`;
三、sql199 标准
select 字段,...
from 表1
[inner|left outer|right outer|cross]join 表2 on 连接条件
[inner|left outer|right outer|cross]join 表3 on 连接条件
[where 筛选条件]
[group by 分组字段]
[having 分组后的筛选条件]
[order by 排序的字段或表达式]
好处:语句上,连接条件和筛选条件实现了分离,简洁明了!
进阶 7:子查询
含义:
一条查询语句中又嵌套了另一条完整的 select 语句,其中被嵌套的 select 语句,称为子查询或内查询
在外面的查询语句,称为主查询或外查询
特点:
-
子查询都放在小括号内
-
子查询可以放在 from 后面、select 后面、where 后面、having 后面,但一般放在条件的右侧
-
子查询优先于主查询执行,主查询使用了子查询的执行结果
-
子查询根据查询结果的行数不同分为以下两类:
单行子查询
结果集只有一行
一般搭配单行操作符使用:> < = <> >= <=
非法使用子查询的情况:
- 子查询的结果为一组值
- 子查询的结果为空
多行子查询
结果集有多行
一般搭配多行操作符使用:any、all、in、not in
in: 属于子查询结果中的任意一个就行
any 和 all 往往可以用其他查询代替
进阶 8:分页查询
应用场景:
web 项目中需要根据用户的需求提交对应的分页查询的 sql 语句
语法:
select 字段|表达式,...
from 表
[where 条件]
[group by 分组字段]
[having 条件]
[order by 排序的字段]
limit [起始的条目索引,]条目数;
特点:
-
起始条目索引从 0 开始
-
limit 子句放在查询语句的最后
-
公式:select * from 表 limit (page-1)*sizePerPage,sizePerPage
假如:
每页显示条目数 sizePerPage
要显示的页数 page
进阶 9:联合查询
引入:
union 联合、合并
语法:
select 字段|常量|表达式|函数 [from 表] [where 条件] union [all]
select 字段|常量|表达式|函数 [from 表] [where 条件] union [all]
select 字段|常量|表达式|函数 [from 表] [where 条件] union [all]
.....
select 字段|常量|表达式|函数 [from 表] [where 条件]
特点:
-
多条查询语句的查询的列数必须是一致的
-
多条查询语句的查询的列的类型几乎相同
-
union 代表去重,union all 代表不去重
DML 语句
插入
语法:
# 方式一
insert into 表名(字段名,...)
values(值1,...);
# 方式二
insert into 表名
set 列名=值,列名=值,...;
特点:
-
字段类型和值类型一致或兼容,而且一一对应
-
可以为空的字段,可以不用插入值,或用 null 填充
-
不可以为空的字段,必须插入值
-
字段个数和值的个数必须一致
-
字段可以省略,但默认所有字段,并且顺序和表中的存储顺序一致
修改
修改单表语法:
update 表名 set 字段=新值,字段=新值
[where 条件]
修改多表语法:
update 表1 别名1,表2 别名2
set 字段=新值,字段=新值
where 连接条件
and 筛选条件
可以理解为把 select 改成 set 并变换位置
删除
方式一:delete 语句
单表的删除:
delete from 表名
[where 筛选条件]
多表的删除:
delete 别名1,别名2
from 表1 别名1,表2 别名2
where 连接条件
and 筛选条件;
方式二:truncate 语句
truncate table 表名
两种方式的区别【面试题】
-
truncate 不能加 where 条件,而 delete 可以加 where 条件
-
truncate 的效率高一丢丢
-
truncate 删除带自增长的列的表后,如果再插入数据,数据从 1 开始 delete 删除带自增长列的表后,如果再插入数据,数据从上一次的断点处开始
-
truncate 删除不能回滚,delete 删除可以回滚
DDL 语句
库和表的管理
库的管理:
# 创建库
create database [if not exists] 库名;
# 删除库
drop database [if exists] 库名;
# 修改字符集
alter database 库名 character set utf8;
表的管理:
# 创建表
create table if not exists 表名(
字段名 字段的类型[(长度) 约束],
字段名 字段的类型[(长度) 约束],
字段名 字段的类型[(长度) 约束],
...
字段名 字段的类型[(长度) 约束]
);
# 修改表名
alter table 原表名 rename [to] 新表名;
# 修改表内字段
# add 添加字段
alter table 表名 add column 字段名 字段类型 [约束];
# modify 修改字段类型和约束
alter table 表名 modify column 字段名 [字段类型] [约束];
# drop 删除字段
alter table 表名 drop column 字段名;
# change 修改字段名
alter table 表名 change column 原字段名 新字段名 字段类型 [约束];
# 删除表
drop table [if exists] studentinfo;
# 复制表结构
create table 新表名 like 旧表名;
# 复制表结构和内容
create table 新表名 select * from 旧表名;
常见类型
数值型:
整型:Tinyint、Smallint、Mediumint、Int/integer、Bigint
小数:
浮点型:float、double
定点型:dec、decimal
字符型:
较短的文本:char、varchar
较长的文本:text、blob
日期型:
date、datetime、timestamp、time、year
常见约束
not null # 非空约束:用于保证该字段不能为空
default # 默认约束:用于保证该字段有默认值
unique #唯一约束:用于保证该字段的值具有唯一性且可空
check # 检查约束:mysql不支持
primary key # 主键约束:用于保证该字段的值具有唯一性且非空
foreign key # 外键约束:用于限制两个表的关系,该字段必须来自于主表的关联字段的值
列级约束
# 直接在字段名和类型后面追加即可
# 只支持:默认、非空、主键、唯一
字段名 字段的类型[(长度) 约束]
表级约束
# 在各个字段最下面,主要写外键约束
[constraint 约束名] 约束类型(字段名);
[constraint 约束名] foreign key(字段名) references 主表名(外键字段名);
标识列
又称为自增长列
含义:可以不用手动地插入值,系统提供默认的序列值
关键字:auto_increment
特点:
-
标识列必须和主键搭配吗?不一定,但要求是一个 key
-
一个表中最多一个标识列
-
标识列只能是数字型
-
标识列可以通过 set auto_increment_increment=3;设置步长,可以通过手动插入值设置起始值
事务
通过一组逻辑操作单元(一组 DML——sql 语句),将数据从一种状态切换到另外一种状态
特点
(ACID)
-
原子性:要么都执行,要么都回滚
-
一致性:保证数据的状态操作前和操作后保持一致
-
隔离性:多个事务同时操作相同数据库的同一个数据时,一个事务的执行不受另外一个事务的干扰
-
持久性:一个事务一旦提交,则数据将持久化到本地,除非其他事务对其进行修改
相关步骤:
- 开启事务
- 编写事务的一组逻辑操作单元(多条 sql 语句)
- 提交事务或回滚事务
事务的分类
隐式事务,没有明显的开启和结束事务的标志
比如 insert、update、delete 语句本身就是一个事务
显式事务,具有明显的开启和结束事务的标志
# 1、开启事务
set autocommit=0;
start transaction;# 可选
# 取消自动提交事务的功能
# 2、编写事务的一组逻辑操作单元(多条sql语句)
insert
update
delete
...
#3、提交事务或回滚事务
commit;
rollback;
# 其他
savepoint # 断点
commit to # 断点
rollback to # 断点
事务的隔离级别
事务并发问题如何发生?
- 当多个事务同时操作同一个数据库的相同数据时
事务的并发问题有哪些?
- 脏读:一个事务读取到了另外一个事务未提交的数据
- 不可重复读:同一个事务中,多次读取到的数据不一致
- 幻读:一个事务读取数据时,另外一个事务进行更新,导致第一个事务读取到了没有更新的数据
如何避免事务的并发问题?
- 通过设置事务的隔离级别
- read uncommitted
- read committed 可以避免脏读
- repeatale read 可以避免脏读、不可重复读和一部分幻读
- serializable 可以避免脏读、不可重复读和幻读
设置隔离级别:
set session|global transaction isolation level 隔离级别名;
查看隔离级别:
select @@tx_isolation;
视图
含义:理解成一张虚拟的表
视图和表的区别:
使用方式 | 占用物理空间 | |
---|---|---|
视图 | 完全相同 | 不占用,仅仅保存的是 sql 逻辑 |
表 | 完全相同 | 占用 |
视图的好处:
-
sql 语句提高重用性,效率高
-
和表实现了分离,提高了安全性
视图的创建
# 语法
CREATE VIEW 视图名
AS
查询语句;
视图的更新
# 方式一
CREATE OR REPLACE VIEW test_v7
AS
SELECT last_name FROM employees
WHERE employee_id>100;
# 方式二
ALTER VIEW test_v7
AS
SELECT employee_id FROM employees;
视图的删除
DROP VIEW test_v1,test_v2,test_v3;
视图结构的查看
DESC test_v7;
SHOW CREATE VIEW test_v7;
视图数据的增删改查
# 查看视图的数据
SELECT * FROM my_v4;
SELECT * FROM my_v1 WHERE last_name='Partners';
# 插入视图的数据
INSERT INTO my_v4(last_name,department_id) VALUES('虚竹',90);
# 修改视图的数据
UPDATE my_v4 SET last_name ='梦姑' WHERE last_name='虚竹';
# 删除视图的数据
DELETE FROM my_v4;
某些视图不能更新
-
包含以下关键字的 sql 语句:分组函数、distinct、group by、having、union 或者 union all
-
常量视图
-
Select 中包含子查询
-
join
-
from 一个不能更新的视图
-
where 子句的子查询引用了 from 子句中的表
存储
含义:一组经过预先编译的 sql 语句的集合 好处:
1、提高了 sql 语句的重用性,减少了开发程序员的压力 2、提高了效率 3、减少了传输次数
分类:
-
无返回无参
-
仅仅带 in 类型,无返回有参
-
仅仅带 out 类型,有返回无参
-
既带 in 又带 out,有返回有参
-
带 inout,有返回有参
注意:in、out、inout 都可以在一个存储过程中带多个
创建存储过程
语法:
create procedure 存储过程名(in|out|inout 参数名 参数类型,...)
begin
存储过程体
end
类似于方法:
修饰符 返回类型 方法名(参数类型 参数名,...){
方法体;
}
注意
# 需要设置新的结束标记
delimiter 新的结束标记
# 示例:
delimiter $
CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名 参数类型,...)
BEGIN
sql语句1;
sql语句2;
END $
# 存储过程体中可以有多条sql语句,如果仅仅一条sql语句,则可以省略begin end
# 参数前面的符号的意思
in:该参数只能作为输入 (该参数不能做返回值)
out:该参数只能作为输出(该参数只能做返回值)
inout:既能做输入又能做输出
调用存储过程
call 存储过程名(实参列表)
函数
创建函数
学过的函数:LENGTH、SUBSTR、CONCAT 等 语法:
CREATE FUNCTION 函数名(参数名 参数类型,...) RETURNS 返回类型
BEGIN
函数体
END
调用函数
SELECT 函数名(实参列表)
函数和存储过程的区别
关键字 | 调用语法 | 返回值 | 应用场景 | |
---|---|---|---|---|
函数 | FUNCTION | SELECT | 函数() 只能是一个 | 一般用于查询结果为一个值并返回时,当有返回值而且仅仅一个 |
存储过程 | PROCEDURE | CALL | 存储过程() 可以有 0 个或多个 | 一般用于更新 |
流程控制结构
系统变量
一、全局变量
作用域:针对于所有会话(连接)有效,但不能跨重启
# 查看所有全局变量
SHOW GLOBAL VARIABLES;
# 查看满足条件的部分系统变量
SHOW GLOBAL VARIABLES LIKE '%char%';
# 查看指定的系统变量的值
SELECT @@global.autocommit;
# 为某个系统变量赋值
SET @@global.autocommit=0;
SET GLOBAL autocommit=0;
二、会话变量
作用域:针对于当前会话(连接)有效
# 查看所有会话变量
SHOW SESSION VARIABLES;
# 查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE '%char%';
# 查看指定的会话变量的值
SELECT @@autocommit;
SELECT @@session.tx_isolation;
# 为某个会话变量赋值
SET @@session.tx_isolation='read-uncommitted';
SET SESSION tx_isolation='read-committed';
自定义变量
一、用户变量
声明并初始化:
SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;
赋值:
方式一:一般用于赋简单的值
SET 变量名=值;
SET 变量名:=值;
SELECT 变量名:=值;
方式二:一般用于赋表 中的字段值
SELECT 字段名或表达式 INTO 变量
FROM 表;
使用:
select @变量名;
二、局部变量
声明:
declare 变量名 类型 [default 值];
赋值:
方式一:一般用于赋简单的值
SET 变量名=值;
SET 变量名:=值;
SELECT 变量名:=值;
方式二:一般用于赋表 中的字段值
SELECT 字段名或表达式 INTO 变量
FROM 表;
使用:
select 变量名
二者的区别:
作用域 | 定义位置 | 语法 | |
---|---|---|---|
用户变量 | 当前会话 | 会话的任何地方 | 加@符号,不用指定类型 |
局部变量 | 定义它的 BEGIN END 中 | BEGIN END 的第一句话 | 一般不用加@,需要指定类型 |
分支
一、if 函数
语法:
if(条件,值1,值2)
特点:可以用在任何位置
二、case 语句
语法:
# 情况一:类似于switch
# (如果是语句,需要加分号)
# (如果是放在begin end中需要加上case,如果放在select后面不需要)
case 表达式
when 值1 then 结果1或语句1
when 值2 then 结果2或语句2
...
else 结果n或语句n
end [case]
# 情况二:类似于多重if
# (如果是语句,需要加分号)
# (如果是放在begin end中需要加上case,如果放在select后面不需要)
case
when 条件1 then 结果1或语句1
when 条件2 then 结果2或语句2
...
else 结果n或语句n
end [case]
特点:可以用在任何位置
三、if elseif 语句
语法:
if 情况1 then 语句1;
elseif 情况2 then 语句2;
...
else 语句n;
end if;
特点:只能用在 begin end 中!
三者比较:
应用场合 | |
---|---|
if 函数 | 简单双分支 |
case 结构 | 等值判断 的多分支 |
if 结构 | 区间判断 的多分支 |
循环
语法:
[标签:] WHILE 循环条件 DO
循环体
END WHILE [标签];
特点:
-
只能放在 BEGIN END 里面
-
如果要搭配 leave 跳转语句,需要使用标签,否则可以不用标签
-
leave 类似于 java 中的 break 语句,跳出所在循环!!!