Tian Jiale's Blog

MySQL 数据库

数据库的好处

  1. 持久化数据到本地

  2. 可以实现结构化查询,方便管理

数据库相关概念

  1. DB:数据库,保存一组有组织的数据的容器

  2. DBMS:数据库管理系统,又称为数据库软件(产品),用于管理 DB 中的数据

  3. SQL:结构化查询语言,用于和 DBMS 通信的语言

数据库存储数据的特点

  1. 将数据放到表中,表再放到库中

  2. 一个数据库中可以有多个表,每个表都有一个的名字,用来标识自己。表名具有唯一性。

  3. 表具有一些特性,这些特性定义了数据在表中如何存储,类似 java 中 “类”的设计。

  4. 表由列组成,我们也称为字段。所有表都是由一个或多个列组成的,每一列类似 java 中的”属性”

  5. 表中的数据是按行存储的,每一行类似于 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 的语法规范

  1. 不区分大小写,但建议关键字大写,表名、列名小写

  2. 每条命令最好用分号结尾

  3. 每条命令根据需要,可以进行缩进 或换行

  4. 注释

单行注释:#注释文字

单行注释:– 注释文字

多行注释:/* 注释文字 */

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(要打印的东西);

特点:

  1. 通过 select 查询完的结果 ,是一个虚拟的表格,不是真实存在

  2. 要查询的东西 可以是常量值、可以是表达式、可以是字段、可以是函数

起别名

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:常见函数

一、单行函数

  1. 字符函数

    concat 拼接

    substr 截取子串

    upper 转换成大写

    lower 转换成小写

    trim 去前后指定的空格和字符

    ltrim 去左边空格

    rtrim 去右边空格

    replace 替换

    lpad 左填充

    rpad 右填充

    instr 返回子串第一次出现的索引

    length 获取字节个数

  2. 数学函数

    round 四舍五入

    rand 随机数

    floor 向下取整

    ceil 向上取整

    mod 取余

    truncate 截断

  3. 日期函数

    now 当前系统日期+时间

    curdate 当前系统日期

    curtime 当前系统时间

    str_to_date 将字符转换成日期

    date_format 将日期转换成字符

  4. 流程控制函数

    if 处理双分支

    case 语句 处理多分支,情况 1:处理等值判断,情况 2:处理条件判断

  5. 其他函数

    version 版本

    database 当前库

    user 当前连接用户

二、分组函数

sum 求和

max 最大值

min 最小值

avg 平均值

count 计数

特点:

  1. 以上五个分组函数都忽略 null 值,除了 count(*)

  2. sum 和 avg 一般用于处理数值型 max、min、count 可以处理任何数据类型

  3. 都可以搭配 distinct 使用,用于统计去重后的结果

  4. count 的参数可以支持: 字段、、常量值,一般放 1 建议使用 count()

进阶 5:分组查询

语法:

select 查询的字段,分组函数
from 
group by 分组的字段

特点:

  1. 可以按单个字段分组

  2. 和分组函数一同查询的字段最好是分组后的字段

  3. 分组筛选

    针对的表 位置 关键字
    分组前筛选 原始表 group by 的前面 where
    分组后筛选 分组后的结果集 group by 的后面 having
  4. 可以按多个字段分组,字段之间用逗号隔开

  5. 可以支持排序

  6. having 后可以支持别名

  7. 分组函数做条件肯定放在 having 子句中

  8. 能用分组前筛选的,就优先使用分组前筛选

进阶 6:多表连接查询

笛卡尔乘积:如果连接条件省略或无效则会出现

解决办法:添加上连接条件

一、分类

按年代分类:

  1. sql192 标准:内连接

  2. sql199 标准【推荐】:内连接+外链接(左外、右外)+交叉连接

按功能分类

  1. 内连接

    等值连接、非等值连接、自连接

  2. 外连接

    左外连接、右外连接、全外连接

  3. 交叉连接

二、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 语句,称为子查询或内查询

在外面的查询语句,称为主查询或外查询

特点:

  1. 子查询都放在小括号内

  2. 子查询可以放在 from 后面、select 后面、where 后面、having 后面,但一般放在条件的右侧

  3. 子查询优先于主查询执行,主查询使用了子查询的执行结果

  4. 子查询根据查询结果的行数不同分为以下两类:

    单行子查询

    结果集只有一行

    一般搭配单行操作符使用:> < = <> >= <=

    非法使用子查询的情况:

    1. 子查询的结果为一组值
    2. 子查询的结果为空

    多行子查询

    结果集有多行

    一般搭配多行操作符使用:any、all、in、not in

    in: 属于子查询结果中的任意一个就行

    any 和 all 往往可以用其他查询代替

进阶 8:分页查询

应用场景:

web 项目中需要根据用户的需求提交对应的分页查询的 sql 语句

语法:

select 字段|表达式,...
from 
[where 条件]
[group by 分组字段]
[having 条件]
[order by 排序的字段]
limit [起始的条目索引,]条目数;

特点:

  1. 起始条目索引从 0 开始

  2. limit 子句放在查询语句的最后

  3. 公式: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 条件]

特点:

  1. 多条查询语句的查询的列数必须是一致的

  2. 多条查询语句的查询的列的类型几乎相同

  3. union 代表去重,union all 代表不去重

DML 语句

插入

语法:

# 方式一
insert into 表名(字段名,...)
values(1...);
# 方式二
insert into 表名
set 列名=,列名=,...;

特点:

  1. 字段类型和值类型一致或兼容,而且一一对应

  2. 可以为空的字段,可以不用插入值,或用 null 填充

  3. 不可以为空的字段,必须插入值

  4. 字段个数和值的个数必须一致

  5. 字段可以省略,但默认所有字段,并且顺序和表中的存储顺序一致

修改

修改单表语法:

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 表名

两种方式的区别【面试题】

  1. truncate 不能加 where 条件,而 delete 可以加 where 条件

  2. truncate 的效率高一丢丢

  3. truncate 删除带自增长的列的表后,如果再插入数据,数据从 1 开始 delete 删除带自增长列的表后,如果再插入数据,数据从上一次的断点处开始

  4. 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

特点:

  1. 标识列必须和主键搭配吗?不一定,但要求是一个 key

  2. 一个表中最多一个标识列

  3. 标识列只能是数字型

  4. 标识列可以通过 set auto_increment_increment=3;设置步长,可以通过手动插入值设置起始值

事务

通过一组逻辑操作单元(一组 DML——sql 语句),将数据从一种状态切换到另外一种状态

特点

(ACID)

  1. 原子性:要么都执行,要么都回滚

  2. 一致性:保证数据的状态操作前和操作后保持一致

  3. 隔离性:多个事务同时操作相同数据库的同一个数据时,一个事务的执行不受另外一个事务的干扰

  4. 持久性:一个事务一旦提交,则数据将持久化到本地,除非其他事务对其进行修改

相关步骤:

  1. 开启事务
  2. 编写事务的一组逻辑操作单元(多条 sql 语句)
  3. 提交事务或回滚事务

事务的分类

隐式事务,没有明显的开启和结束事务的标志

比如 insert、update、delete 语句本身就是一个事务

显式事务,具有明显的开启和结束事务的标志

# 1、开启事务
set autocommit=0;
start transaction;# 可选
# 取消自动提交事务的功能

# 2、编写事务的一组逻辑操作单元(多条sql语句)
insert
update
delete
...

#3、提交事务或回滚事务
commit;
rollback;

# 其他
savepoint  # 断点
commit to # 断点
rollback to # 断点

事务的隔离级别

事务并发问题如何发生?

  • 当多个事务同时操作同一个数据库的相同数据时

事务的并发问题有哪些?

  • 脏读:一个事务读取到了另外一个事务未提交的数据
  • 不可重复读:同一个事务中,多次读取到的数据不一致
  • 幻读:一个事务读取数据时,另外一个事务进行更新,导致第一个事务读取到了没有更新的数据

如何避免事务的并发问题?

  • 通过设置事务的隔离级别
    1. read uncommitted
    2. read committed 可以避免脏读
    3. repeatale read 可以避免脏读、不可重复读和一部分幻读
    4. serializable 可以避免脏读、不可重复读和幻读

设置隔离级别:

set session|global transaction isolation level 隔离级别名;

查看隔离级别:

select @@tx_isolation;

视图

含义:理解成一张虚拟的表

视图和表的区别:

使用方式 占用物理空间
视图 完全相同 不占用,仅仅保存的是 sql 逻辑
完全相同 占用

视图的好处:

  1. sql 语句提高重用性,效率高

  2. 和表实现了分离,提高了安全性

视图的创建

# 语法
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;

某些视图不能更新

  1. 包含以下关键字的 sql 语句:分组函数、distinct、group by、having、union 或者 union all

  2. 常量视图

  3. Select 中包含子查询

  4. join

  5. from 一个不能更新的视图

  6. where 子句的子查询引用了 from 子句中的表

存储

含义:一组经过预先编译的 sql 语句的集合 好处:

1、提高了 sql 语句的重用性,减少了开发程序员的压力 2、提高了效率 3、减少了传输次数

分类:

  1. 无返回无参

  2. 仅仅带 in 类型,无返回有参

  3. 仅仅带 out 类型,有返回无参

  4. 既带 in 又带 out,有返回有参

  5. 带 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 [标签];

特点:

  1. 只能放在 BEGIN END 里面

  2. 如果要搭配 leave 跳转语句,需要使用标签,否则可以不用标签

  3. leave 类似于 java 中的 break 语句,跳出所在循环!!!