当前位置:   article > 正文

Mysql修炼之路---练气篇_mysql 修炼

mysql 修炼

1. 数据库基本概念

  1. 数据(Data) 是指对客观事物进行描述并可以鉴别的符号,这些符号是可识别的、抽象的。它不仅仅指狭义上的数字,而是有多种表现形式:字母、文字、文本、图形、音频、视频等。现在计算机存储和处理的数据范围十分广泛,而描述这些数据的符号也变得越来越复杂了。
  2. 数据库(Database,DB)指的是以一定格式存放、能够实现多个用户共享、与应用程序彼此独立的数据集合。
  3. 数据库管理系统(Database Management System,DBMS)是用来定义和管理数据的软件。如何科学的组织和存储数据,如何高效的获取和维护数据,如何保证数据的安全性和完整性,这些都需要靠数据库管理系统完成。目前,比较流行的数据库管理系统有:Oracle、MySQL、SQL Server、DB2等。
  4. 数据库应用程序(Database Application System,DBAS) 在数据库管理系统基础上,使用数据库管理系统的语法,开发的直接面对最终用户的应用程序,如学生管理系统、人事管理系统、图书管理系统等。
  5. 数据库管理员(Database Administrator,DBA)指的是以一定格式存放、能够实现多个用户共享、与应用程序彼此独立的数据集合。
  6. 最终用户(User)指的是数据库应用程序的使用者。用户面向的是数据库应用程序(通过应用程序操作数据),并不会直接与数据库打交道。
  7. 数据库系统(Database System,DBS)一般是由数据库、数据库管理系统、数据库应用程序、数据库管理员和最终用户构成。其中DBMS是数据库系统的基础和核心。

2. 数据库类型

  • 据库经过几十年的发展,出现了多种类型。根据数据的组织结构不同,主要分为网状数据库、层次数据库、关系型数据库和非关系型数据库四种。目前最常见的数据库模型主要是:关系型数据库和非关系型数据库
  • 关系型数据库:关系型数据库模型是将复杂的数据结构用较为简单的二元关系(二维表)来表示,如图1-4所示。在该类型数据库中,对数据的操作基本上都建立在一个或多个表格上,我们可以采用结构化查询语言(SQL)对数据库进行操作。关系型数据库是目前主流的数据库技术,其中具有代表性的数据库管理系统有:Oracle、DB2、SQL Server、MySQL等。(PS:关系=二维表)
    1. Oracle数据库是由美国的甲骨文(Oracle)公司开发的世界上第一款支持SQL语言的关系型数据库。经过多年的完善与发展,Oracle数据库已经成为世界上最流行的数据库,也是甲骨文公司的核心产品。Oracle数据库具有很好的开放性,能在所有的主流平台上运行,并且性能高、安全性高、风险低;但是其对硬件的要求很高、管理维护和操作比较复杂而且价格昂贵,所以一般用在满足对银行、金融、保险等行业大型数据库的需求上。
    2. DB2是IBM公司著名的关系型数据库产品。DB2无论稳定性,安全性,恢复性等等都无可挑剔,而且从小规模到大规模的应用都可以使用,但是用起来非常繁琐,比较适合大型的分布式应用系统。
    3. SQL Server是由Microsoft开发和推广的关系型数据库,SQL Server的功能比较全面、效率高,可以作为中型企业或单位的数据库平台。SQL Server可以与Windows操作系统紧密继承,无论是应用程序开发速度还是系统事务处理运行速度,都能得到大幅度提升。但是,SQL Server只能在Windows系统下运行,毫无开放性可言。
    4. MySQL是一种开放源代码的轻量级关系型数据库,MySQL数据库使用最常用的结构化查询语言(SQL)对数据库进行管理。由于MySQL是开放源代码的,因此任何人都可以在General Public License的许可下下载并根据个人需要对其缺陷进行修改。由于MySQL数据库体积小、速度快、成本低、开放源码等优点,现已被广泛应用于互联网上的中小型网站中,并且大型网站也开始使用MySQL数据库,如网易、新浪等。
  • 非关系型数据库:NOSQL(Not Only SQL)泛指非关系型数据库。关系型数据库在超大规模和高并发的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题。NOSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。常见的非关系型数据库管理系统有MemcachedMongoDBredisHBase

3. MySQL介绍

  • MySQL数据库最初是由瑞典MySQL AB公司开发,2008年1月16号被Sun公司收购。2009年,SUN又被Oracle收购。MySQL是目前IT行业最流行的开放源代码的数据库管理系统,同时它也是一个支持多线程高并发多用户的关系型数据库管理系统。MySQL之所以受到业界人士的青睐,主要是因为其具有以下几方面优点:
    1. 开放源代码:MySQL最强大的优势之一在于它是一个开放源代码的数据库管理系统。开源的特点是给予了用户根据自己需要修改DBMS的自由。MySQL采用了General Public License,这意味着授予用户阅读、修改和优化源代码的权利,这样即使是免费版的MySQL的功能也足够强大,这也是为什么MySQL越来越受欢迎的主要原因。
    2. 跨平台:MySQL可以在不同的操作系统下运行,简单地说,MySQL可以支持Windows系统、UNIX系统、Linux系统等多种操作系统平台。这意味着在一个操作系统中实现的应用程序可以很方便地移植到其他的操作系统下。
    3. 轻量级:MySQL的核心程序完全采用多线程编程,这些线程都是轻量级的进程,它在灵活地为用户提供服务的同时,又不会占用过多的系统资源。因此MySQL能够更快速、高效的处理数据。
    4. 成本低:MySQL分为社区版和企业版,社区版是完全免费的,而企业版是收费的。即使在开发中需要用到一些付费的附加功能,价格相对于昂贵的Oracle、DB2等也是有很大优势的。其实免费的社区版也支持多种数据类型和正规的SQL查询语言,能够对数据进行各种查询、增加、删除、修改等操作,所以一般情况下社区版就可以满足开发需求了,而对数据库可靠性要求比较高的企业可以选择企业版。
    5. 另外,PHP中提供了一整套的MySQL函数,对MySQL进行了全方位的强力支持。 总体来说,MySQL是一款开源的、免费的、轻量级的关系型数据库,其具有体积小、速度快、成本低、开放源码等优点,其发展前景是无可限量的。
    6. PS:社区版与企业版主要的区别是:
      • 社区版包含所有MySQL的最新功能,而企业版只包含稳定之后的功能。换句话说,社区版可以理解为是企业版的测试版。
      • MySQL官方的支持服务只是针对企业版,如果用户在使用社区版时出现了问题,MySQL官方是不负责任的。
  • MySQL的版本:近期主要历史版本有5.0/5.1/5.5/5.6/5.7,目前最新版本是MySQL8,2016-09-12第一个DM(development milestone)版本8.0.0发布。6.0曾经是个内部试验版本,已经取消了。

4. SQL语言入门

4.1 sql简介

  1. SQL(Structured Query Language)是结构化查询语言的简称,它是一种数据库查询和程序设计语言,同时也是目前使用最广泛的关系型数据库操作语言。在数据库管理系统中,使用SQL语言来实现数据的存取、查询、更新等功能。SQL是一种非过程化语言,只需提出“做什么”,而不需要指明“怎么做”。
  2. SQL是由IBM公司在1974~1979年之间根据E.J.Codd发表的关系数据库理论为基础开发的,其前身是“SEQUEL”,后更名为SQL。由于SQL语言具有集数据查询、数据操纵、数据定义和数据控制功能于一体,类似自然语言、简单易用以及非过程化等特点,得到了快速的发展,并于1986年10月,被美国国家标准协会(American National Standards Institute,ANSI)采用为关系数据库管理系统的标准语言,后为国际标准化组织(International Organization for Standardization,ISO)采纳为国际标准。

4.2 数据类型(data_type)

  • 规定了列可容纳何种数据类型。下面的表格包含了SQL中最常用的数据类型

    常用数据类型大小描述
    INT/INTEGER4字节(-2147483648,2147483647)大整数值
    CHAR(M)0~255字符允许长度0~M个字符的定长字符串
    VARCHAR(M)0~65535字符允许长度0~M个字符的变长字符串
    BLOBbinary large object二进制形式的长文本数据
    TEXT长文本数据

4.3 表的完整性约束

  • 为防止不符合规范的数据存入数据库,在用户对数据进行插入、修改、删除等操作时,MySQL提供了一种机制来检查数据库中的数据是否满足规定的条件,以保证数据库中数据的准确性和一致性,这种机制就是完整性约束。MySQL中主要支持以下几种种完整性约束,如表所示。 其中Check约束是MySQL8中提供的支持

    约束条件约束条件(小写)约束描述
    PRIMARY KEYprimary key主键约束,约束字段的值可唯一地标识对应的记录
    NOT NULLnot null非空约束,约束字段的值不能为空
    UNIQUEunique唯一约束,约束字段的值是唯一的
    CHECKcheck检查约束,限制某个字段的取值范围
    DEFAULTdefault默认值约束,约束字段的默认值
    AUTO_INCREMENTauto_increment自动增加约束,约束字段的值自动递增
    FOREIGN KEYforeign key外键约束,约束表与表之间的关系
  • 约束从作用上可以分为两类:

    1. 表级约束:可以约束表中任意一个或多个字段。与列定义相互独立,不包含在列定义中;与定义用‘,’分隔;必须指出要约束的列的名称;
    2. 列级约束:包含在列定义中,直接跟在该列的其它定义之后 ,用空格分隔;不必指定列名

4.3.1 非外键约束

  • 主键约束(PRIMARY KEY,缩写PK),是数据库中最重要的一种约束,其作用是约束表中的某个字段可以唯一标识一条记录。因此,使用主键约束可以快速查找表中的记录。就像人的身份证、学生的学号等等,设置为主键的字段取值不能重复(唯一),也不能为空(非空),否则无法唯一标识一条记录。主键可以是单个字段,也可以是多个字段组合。对于单字段主键的添加可使用表级约束,也可以使用列级约束;而对于多字段主键的添加只能使用表级约束。
  • 非空约束(NOT NULL,缩写NK)规定了一张表中指定的某个字段的值不能为空(NULL)。设置了非空约束的字段,在插入的数据为NULL时,数据库会提示错误,导致数据无法插入。无论是单个字段还是多个字段非空约束的添加只能使用列级约束(非空约束无表级约束)
-- 为已存在表中的字段添加非空约束 
alter table student8 modify stu_sex varchar(1) not null;
-- 使用ALTER TABLE语句删除非空约束 
alter  table student8 modify stu_sex varchar(1) null;
  • 1
  • 2
  • 3
  • 4
  • 唯一约束(UNIQUE,缩写UK)比较简单,它规定了一张表中指定的某个字段的值不能重复,即这一字段的每个值都是唯一的。如果想要某个字段的值不重复,那么就可以为该字段添加为唯一约束。无论单个字段还是多个字段唯一约束的添加均可使用列级约束和表级约束
  • 检查约束(CHECK)用来限制某个字段的取值范围,可以定义为列级约束,也可以定义为表级约束。MySQL8开始支持检查约束。
  • 默认值约束(DEFAULT)用来规定字段的默认值。如果某个被设置为DEFAULT约束的字段没插入具体值,那么该字段的值将会被默认值填充。默认值约束的设置与非空约束一样,也只能使用列级约束。
  • 自增约束(AUTO_INCREMENT)可以使表中某个字段的值自动增加。一张表中只能有一个自增长字段,并且该字段必须定义了约束(该约束可以是主键约束、唯一约束以及外键约束),如果自增字段没有定义约束,数据库则会提示“Incorrect table definition; there can be only one auto column and it must be defined as a key”错误。由于自增约束会自动生成唯一的ID,所以自增约束通常会配合主键使用,并且只适用于整数类型。一般情况下,设置为自增约束字段的值会从1开始,每增加一条记录,该字段的值加1
-- 为已存在表中的字段添加自增约束 
/*创建表student11*/
 create   table student11 (
       stu_id int(10) primary key,
       stu_name varchar(3),
       stu_sex varchar (1)
);
/*为student11表中的主键字段添加自增约束*/
alter   table student11 modify stu_id int(10) auto_increment;
-- 使用ALTER TABLE语句删除自增约束 
alter   table studen11 modify stu_id int(10);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

4.3.2 外键约束

  • 外键约束(FOREIGN KEY,缩写FK)是用来实现数据库表的参照完整性的。外键约束可以使两张表紧密的结合起来,特别是针对修改或者删除的级联操作时,会保证数据的完整性。外键是指表中某个字段的值依赖于另一张表中某个字段的值,而被依赖的字段必须具有主键约束或者唯一约束。被依赖的表我们通常称之为父表或者主表,设置外键约束的表称为子表或者从表。
-- 先创建父表:班级表:
create table t_class(
        cno int(4) primary key auto_increment,
        cname varchar(10) not null,
        room char(4)
)
-- 添加班级数据:
insert into t_class values (null,'java001','r803');
insert into t_class values (null,'java002','r416');
insert into t_class values (null,'大数据001','r103');
-- 可以一次性添加多条记录:
insert into t_class values (null,'java001','r803'),(null,'java002','r416'),(null,'大数据001','r103');
-- 查询班级表:
select * from t_class;
-- 学生表删除:
drop table t_student;
-- 创建子表,学生表:
create table t_student(
        sno int(6) primary key auto_increment, 
        sname varchar(5) not null, 
        classno int(4)  -- 取值参考t_class表中的cno字段,不要求字段名字完全重复,但是类型长度定义 尽量要求相同。
);
-- 添加学生信息:
insert into t_student values (null,'张三',1),(null,'李四',1),(null,'王五',2);
-- 查看学生表:
select * from t_student;
-- 出现问题:
-- 1.添加一个学生对应的班级编码为4:
insert into t_student values (null,'丽丽',4);
-- 2.删除班级2:
delete from t_class where cno = 2;
-- 出现问题的原因:
-- 因为你现在的外键约束,没用语法添加进去,现在只是逻辑上认为班级编号是外键,没有从语法上定义
-- 解决办法,添加外键约束:
-- 注意:外键约束只有表级约束,没有列级约束:
create table t_student(
        sno int(6) primary key auto_increment, 
        sname varchar(5) not null, 
        classno int(4),-- 取值参考t_class表中的cno字段,不要求字段名字完全重复,但是类型长度定义 尽量要求相同。
                                constraint fk_stu_classno foreign key (classno) references t_class (cno)
);
create table t_student(
        sno int(6) primary key auto_increment, 
        sname varchar(5) not null, 
        classno int(4)
);
-- 在创建表以后添加外键约束:
alter table t_student add constraint fk_stu_classno foreign key (classno) references t_class (cno)
-- 上面的两个问题都解决了:
-- 添加学生信息:
-- > 1452 - Cannot add or update a child row: a foreign key constraint fails (`mytestdb`.`t_student`, CONSTRAINT `fk_stu_classno` FOREIGN KEY (`classno`) REFERENCES `t_class` (`cno`))
insert into t_student values (null,'张三',1),(null,'李四',1),(null,'王五',2);
-- 删除班级1:
-- 2.删除班级2:
insert into t_student values (null,'张三',3),(null,'李四',3),(null,'王五',3);
-- > 1451 - Cannot delete or update a parent row: a foreign key constraint fails (`mytestdb`.`t_student`, CONSTRAINT `fk_stu_classno` FOREIGN KEY (`classno`) REFERENCES `t_class` (`cno`))
delete from t_class where cno = 3;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 外键策略
-- 学生表删除:
drop table t_student;
-- 班级表删除:
drop table t_class;
-- 注意:先删除从表,再删除主表。(视频中这个位置笔误,笔记现在已经更正)
-- 先创建父表:班级表:
create table t_class(
        cno int(4) primary key auto_increment,
        cname varchar(10) not null,
        room char(4)
)
-- 可以一次性添加多条记录:
insert into t_class values (null,'java001','r803'),(null,'java002','r416'),(null,'大数据001','r103');
-- 添加学生表,添加外键约束:
create table t_student(
        sno int(6) primary key auto_increment, 
        sname varchar(5) not null, 
        classno int(4),-- 取值参考t_class表中的cno字段,不要求字段名字完全重复,但是类型长度定义 尽量要求相同。
                                constraint fk_stu_classno foreign key (classno) references t_class (cno)
);
-- 可以一次性添加多条记录:
insert into t_student values (null,'张三',1),(null,'李四',1),(null,'王五',2),(null,'朱六',3);
-- 查看班级表和学生表:
select * from t_class;
select * from t_student;
-- 删除班级2:如果直接删除的话肯定不行因为有外键约束:
-- 加入外键策略:
-- 策略1:no action 不允许操作
-- 通过操作sql来完成:
-- 先把班级2的学生对应的班级 改为null 
update t_student set classno = null where classno = 2;
-- 然后再删除班级2:
delete from t_class where cno = 2;
-- 策略2:cascade 级联操作:操作主表的时候影响从表的外键信息:
-- 先删除之前的外键约束:
alter table t_student drop foreign key fk_stu_classno;
-- 重新添加外键约束:
alter table t_student add constraint fk_stu_classno foreign key (classno) references t_class (cno) on update cascade on delete cascade;
-- 试试更新:
update t_class set cno = 5 where cno = 3;
-- 试试删除:
delete from t_class where cno = 5;
-- 策略3:set null  置空操作:
-- 先删除之前的外键约束:
alter table t_student drop foreign key fk_stu_classno;
-- 重新添加外键约束:
alter table t_student add constraint fk_stu_classno foreign key (classno) references t_class (cno) on update set null on delete set null;
-- 试试更新:
update t_class set cno = 8 where cno = 1;
-- 注意:
-- 1. 策略2 级联操作  和  策略2 的  删除操作  可以混着使用:
alter table t_student add constraint fk_stu_classno foreign key (classno) references t_class (cno) on update cascade on delete set null ;
-- 2.应用场合:
-- (1)朋友圈删除,点赞。留言都删除  --  级联操作
-- (2)解散班级,对应的学生 置为班级为null就可以了,-- set null
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

5. SQL语言基础使用

5.1 DQL数据查询语言

  • DQL主要用于数据的查询,其基本结构是使用SELECT子句,FROM子句和WHERE子句的组合来查询一条或多条数据。

5.1.1 DQL语法

-- 语法
select column, group_function(column) 
from tabletable name)
[where condition] 
[group by  group_by_expression] 
[having group_condition] 
[order by column]; 
-- 执行顺序
from--where--group by–select--having--order by

-- SELECT 语句用于从表中选取数据,结果被存储在一个结果表中(称为结果集)注意: 星号(*)是选取所有列的快捷方式
SELECT * FROM 表名称;
-- 指定所要查询数据的列
SELECT 列名称 FROM 表名称;

-- 通过使用 SQL,可以为列名称和表名称指定别名(Alias),别名使查询程序更易阅读和书写
-- 表别名:
SELECT 列名称/(*) FROM 表名称 AS 别名;
-- 列别名:
SELECT 列名称 as 别名 FROM 表名称;
-- 注意: 实际应用时,这个 AS 可以省略,但是列别名需要加上 " "
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

5.1.2 WHERE子句

操作符描述
=等于
<> / !=不等于
‘>’大于
<小于
‘>=’大于等于
<=小于等于
BETWEEN在某个范围内
LIKE搜索某种模式(’_‘ 1, ‘%’ N)
AND如果第一个条件和第二个条件都成立,则 AND 运算符显示一条记录
OR如果第一个条件和第二个条件中只要有一个成立,则 OR 运算符显示一条记录
DISTINCT去除重复值
IN锁定多个值
BINARY查询结果区分大小写
-- 如果需要从表中选取指定的数据,可将 WHERE 子句添加到 SELECT 语句
SELECT 列名称 FROM 表名称 WHERE 列 运算符 值;

-- AND 运算符:如果第一个条件和第二个条件都成立,则 AND 运算符显示一条记录
SELECT * FROM 表名称 WHERE 列 运算符 值 AND 列 运算符 值;
-- OR 运算符:如果第一个条件和第二个条件中只要有一个成立,则 OR 运算符显示一条记录
SELECT * FROM 表名称 WHERE 列 运算符 值 OR 列 运算符 值;

-- LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式
SELECT 列名/(*) FROM 表名称 WHERE 列名称 LIKE;

-- IN 操作符允许我们在 WHERE 子句中规定多个值
SELECT 列名/(*) FROM 表名称 WHERE 列名称 IN (1,2,3);

-- 操作符 BETWEEN … AND 会选取介于两个值之间的数据范围。这些值可以是数值、文本或者日期
SELECT 列名/(*) FROM 表名称 WHERE 列名称 BETWEEN1 AND2;
-- 查询上述结果相反的结果,可以使用 NOT
SELECT 列名/(*) FROM 表名称 WHERE 列名称 NOT BETWEEN1 AND2;

-- 如果一张表中有多行重复数据,如何去重显示呢?可以了解下 DISTINCT(distinct)
SELECT DISTINCT 列名称 FROM 表名称;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

5.1.3 GROUP BY – 分组

-- GROUP BY 语句用于结合合计函数,根据一个或多个列对结果集进行分组
SELECT 列名A, 统计函数(列名B)
FROM 表名
WHERE 查询条件
GROUP BY 列名A;
  • 1
  • 2
  • 3
  • 4
  • 5

5.1.4 HAVING – 句尾连接

-- 在 SQL 中增加 HAVING 子句原因是,WHERE 关键字无法与合计函数一起使用
SELECT 列名A, 统计函数(列名B)
FROM table_name
WHERE 查询条件
GROUP BY 列名A
HAVING 统计函数(列名B) 查询条件;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5.1.5 ORDER BY 排序

-- ORDER BY 语句用于根据指定的列对结果集进行排序,默认按照升序对记录进行排序,如果您希望按照降序对记录进行排序,可以使用 DESC 关键字
SELECT * FROM 表名称 ORDER BY1,2 DESC;
-- 默认排序为 ASC 升序,DESC 代表降序
  • 1
  • 2
  • 3

5.1.6 函数

  • SQL 拥有很多可用于计数和计算的内建函数

  • 单行函数

    单行函数描述
    UCASE/UPPER函数把字段的值转换为大写
    LCASE/LOWER函数把字段的值转换为小写
    LEN/LENGTH函数返回文本字段中值的长度
    CONCAT(str1, str2, ···, strn)将str1、str2···strn拼接成一个新的字符串
    INSERT(str, index, n, newstr)将字符串str从第index位置开始的n个字符替换成字符串newstr
    LENGTH(str)获取字符串str的长度
    LOWER(str)将字符串str中的每个字符转换为小写
    UPPER(str)将字符串str中的每个字符转换为大写
    LEFT(str, n)获取字符串str最左边的n个字符
    RIGHT(str, n)获取字符串str最右边的n个字符
    LPAD(str, n, pad)使用字符串pad在str的最左边进行填充,直到长度为n个字符为止
    RPAD(str, n, pad)使用字符串pad在str的最右边进行填充,直到长度为n个字符为止
    LTRIM(str)去除字符串str左侧的空格
    RTRIM(str)去除字符串str右侧的空格
    TRIM(str)去除字符串str左右两侧的空格
    REPLACE(str,oldstr,newstr)用字符串newstr替换字符串str中所有的子字符串oldstr
    REVERSE(str)将字符串str中的字符逆序
    STRCMP(str1, str2)比较字符串str1和str2的大小
    SUBSTRING(str,index,n)获取从字符串str的index位置开始的n个字符
    数值函数描述
    ABS(num)返回num的绝对值
    CEIL(num)返回大于num的最小整数(向上取整)
    FLOOR(num)返回小于num的最大整数(向下取整)
    MOD(num1, num2)返回num1/num2的余数(取模)
    PI()返回圆周率的值
    POW(num,n)/POWER(num, n)返回num的n次方
    RAND(num)返回0~1之间的随机数
    ROUND(num, n)返回x四舍五入后的值,该值保留到小数点后n位
    TRUNCATE(num, n)返回num被舍去至小数点后n位的值
    日期与时间函数描述
    CURDATE()返回当前日期
    CURTIME()返回当前时间
    NOW()返回当前日期和时间
    SYSDATE()返回该函数执行时的日期和时间
    DAYOFYEAR(date)返回日期date为一年中的第几天
    WEEK(date)/WEEKOFYEAR(date)返回日期date为一年中的第几周
    DATE_FORMAT(date, format)返回按字符串format格式化后的日期date
    DATE_ADD(date, INTERVAL expr unit) /ADDDATE(date, INTERVAL expr unit)返回date加上一个时间间隔后的新时间值
    DATE_SUB(date, INTERVAL expr unit) /SUBDATE(date, INTERVAL expr unit)返回date减去一个时间间隔后的新时间值
    DATEDIFF(date1, date2)返回起始日期date1与结束日期date2之间的间隔天数
    流程函数间隔类型描述
    IF(condition, t, f)如果条件condition为真,则返回t,否则返回f
    IFNULL(value1, value2)如果value1不为null,则返回value1,否则返回value2
    NULLIF(value1, value2)如果value1等于value2,则返回null,否则返回value1
    CASE value WHEN (value1) THEN result1 (WHEN (value2) THEN result2 …) (ELSE result) END如果value等于value1,则返回result1,···,否则返回result
    CASE WHEN (condition1) THEN result1 (WHEN (condition2) THEN result2 …) (ELSE result) END如果条件condition1为真,则返回result1,···,否则返回result
    JSON函数描述
    JSON_APPEND()在JSON文档中追加数据
    JSON_INSERT ()在JSON文档中插入数据
    JSON_REPLACE ()替换JSON文档中的数据
    JSON_REMOVE ()从JSON文档的指定位置移除数据
    JSON_CONTAINS()判断JSON文档中是否包含某个数据
    JSON_SEARCH()查找JSON文档中给定字符串的路径
    其他函数描述
    DATABASE()返回当前数据库名
    VERSION()返回当前MySQL的版本号
    USER()返回当前登录的用户名
    INET_ATON(IP)返回IP地址的数字表示
    INET_NTOA返回数字代表的IP地址
    PASSWORD(str)实现对字符串str的加密操作
    FORMAT(num, n)实现对数字num的格式化操作,保留n位小数
    CONVERT(data, type)实现将数据data转换成type类型的操作
  • 多行函数

多行函数语义语法
AVG函数返回数值列的平均值。NULL 值不包括在计算中SELECT AVG(列名) FROM 表名;
MAX返回一列中的最大值SELECT MAX(列名) FROM 表名;
MIN返回一列中的最小值SELECT MIN(列名) FROM 表名
SUM返回数值列的总数(求和)SELECT SUM(列名) FROM 表名;
COUNT返回表中的记录数SELECT COUNT(*) FROM 表名;
COUNT返回指定列的不同值的数目SELECT COUNT(DISTINCT 列名) FROM 表名;
COUNT返回指定列的值的数目(NULL 不计入)SELECT COUNT(列名) FROM 表名;

5.1.7 多表查询

5.1.7.1 JOIN – 多表关联
-- JOIN 用于根据两个或多个表中的列之间的关系,从这些表中查询数据。有时为了得到完整的结果,我们需要从两个或更多的表中获取结果。我们就需要执行 join
-- 数据库中的表可通过键将彼此联系起来。主键(Primary Key)是一个列,在这个列中的每一行的值都是唯一的。在表中,每个主键的值都是唯一的。这样做的目的是在不重复每个表中的所有数据的情况下,把表间的数据交叉捆绑在一起。
select 列名
from 表A
INNER|LEFT|RIGHT|FULL JOIN 表B
ON 表A主键列 = 表B外键列;

--不同的 SQL JOIN:
--下面列出了您可以使用的 JOIN 类型,以及它们之间的差异。
-- JOIN: 如果表中有至少一个匹配,则返回行
-- INNER JOIN: 内部连接,返回两表中匹配的行
-- LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
-- RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
-- FULL JOIN: 只要其中一个表中存在匹配,就返回行
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
5.1.7.2 UNION – 合并结果集
-- UNION 操作符用于合并两个或多个 SELECT 语句的结果集
SELECT 列名 FROM 表A
UNION
SELECT 列名 FROM 表B;
-- UNION 操作符默认为选取不同的值。如果查询结果需要显示重复的值,请使用 UNION ALL
SELECT 列名 FROM 表A
UNION ALL
SELECT 列名 FROM 表B;
-- 注意: UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
5.1.7.3 多表查询(交叉连接/自然连接/内连接)
  • 实际开发中往往需要针对两张甚至更多张数据表进行操作,而这多张表之间需要使用主键和外键关联在一起,然后使用连接查询来查询多张表中满足要求的数据记录。一条SQL语句查询多个表,得到一个结果,包含多个表的数据。效率高。在SQL99中,连接查询需要使用join关键字实现。提供了多种连接查询的类型: cross交叉连接 natural自然连接 using内连接 on内连接
select * from emp;
select * from dept;
-- 多表查询
select * 
from emp
cross join dept; -- 14*4=56 笛卡尔乘积:无实际意义,有理论意义

-- 自然链接natural join
-- 自动匹配所有的同名列 ,同名列只展示一次 ,简单
select *
from emp
natural join dept;
-- 查询字段的时候,没有指定字段所属的数据库表,效率低
select empno,ename,sal,dname,loc
from emp
natural join dept;
-- 解决:指定表名
select emp.empno,emp.ename,emp.sal,dept.dname,dept.loc
from emp
natural join dept;
-- 表名太长,可以起别名
select e.empno,e.ename,e.sal,d.dname,d.loc,d.deptno
from emp e
natural join dept d;
-- 自然连接 natural join 缺点:自动匹配表中所有的同名列,但是有时候我们希望只匹配部分同名列:
-- 解决: using子句
select * 
from emp e
inner join dept d  -- inner可以省略
using(deptno)  -- 这里不能写natural join了 ,这里是内连接
-- using缺点:关联的字段,必须是同名的 
-- 解决: 内连接 - on子句:
select *
from emp e
inner join dept d
on (e.deptno = d.deptno)
-- 多表连接查询的类型: 1.交叉连接  cross join  2. 自然连接  natural join  
-- 3. 内连接 - using子句   4.内连接 - on子句
-- 综合看:内连接 - on子句
select * 
from emp e
inner join dept d
on (e.deptno = d.deptno)
where sal > 3500;
-- 条件:
-- 1.筛选条件  where  having
-- 2.连接条件 on,using,natural 
-- SQL99语法 :筛选条件和连接条件是分开的
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
5.1.7.4 多表查询(外连接)
-- inner join - on子句: 显示的是所有匹配的信息
select * 
from emp e
inner join dept d
on e.deptno = d.deptno;
select * from emp;
select * from dept;
-- 问题:
-- 1.40号部分没有员工,没有显示在查询结果中
-- 2.员工scott没有部门,没有显示在查询结果中
-- 外连接:除了显示匹配的数据之外,还可以显示不匹配的数据
-- 左外连接: left outer join   -- 左面的那个表的信息,即使不匹配也可以查看出效果
select * 
from emp e
left outer join dept d
on e.deptno = d.deptno;
-- 右外连接: right outer join   -- 右面的那个表的信息,即使不匹配也可以查看出效果
select * 
from emp e
right outer join dept d
on e.deptno = d.deptno;
-- 全外连接  full outer join -- 这个语法在mysql中不支持,在oracle中支持 -- 展示左,右表全部不匹配的数据 
-- scott ,40号部门都可以看到
select * 
from emp e
full outer join dept d
on e.deptno = d.deptno;
-- 解决mysql中不支持全外连接的问题:
select * 
from emp e
left outer join dept d
on e.deptno = d.deptno
union -- 并集 去重 效率低
select * 
from emp e
right outer join dept d
on e.deptno = d.deptno;
select * 
from emp e
left outer join dept d
on e.deptno = d.deptno
union all-- 并集 不去重 效率高
select * 
from emp e
right outer join dept d
on e.deptno = d.deptno;
-- mysql中对集合操作支持比较弱,只支持并集操作,交集,差集不支持(oracle中支持)
-- outer可以省略不写
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
5.1.7.5 三表联查询
-- 查询员工的编号、姓名、薪水、部门编号、部门名称、薪水等级
select * from emp;
select * from dept;
select * from salgrade;

select e.ename,e.sal,e.empno,e.deptno,d.dname,s.* 
from emp e
right outer join dept d
on e.deptno = d.deptno
inner join salgrade s 
on e.sal between s.losal and s.hisal
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
5.1.7.6 自关联
-- 查询员工的编号、姓名、上级编号,上级的姓名
select * from emp;
select e1.empno 员工编号,e1.ename 员工姓名,e1.mgr 领导编号,e2.ename 员工领导姓名
from emp e1
inner join emp e2
on e1.mgr = e2.empno;
-- 左外连接:
select e1.empno 员工编号,e1.ename 员工姓名,e1.mgr 领导编号,e2.ename 员工领导姓名
from emp e1
left outer join emp e2
on e1.mgr = e2.empno;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

5.1.8 子查询

  • 子查询:一条SQL语句含有多个select
5.1.8.1 不相关子查询
-- 引入子查询:
-- 查询所有比“CLARK”工资高的员工的信息  
-- 步骤1:“CLARK”工资
select sal from emp where ename = 'CLARK'  -- 2450
-- 步骤2:查询所有工资比2450高的员工的信息  
select * from emp where sal > 2450;
-- 两次命令解决问题 --》效率低 ,第二个命令依托于第一个命令,第一个命令的结果给第二个命令使用,但是
-- 因为第一个命令的结果可能不确定要改,所以第二个命令也会导致修改
-- 将步骤1和步骤2合并 --》子查询:
select * from emp where sal > (select sal from emp where ename = 'CLARK');
-- 一个命令解决问题 --》效率高
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 单行子查询
-- 单行子查询:
-- 查询工资高于平均工资的雇员名字和工资。
select ename,sal
from emp
where sal > (select avg(sal) from emp);
-- 查询和CLARK同一部门且比他工资低的雇员名字和工资。
select ename,sal
from emp
where deptno = (select deptno from emp where ename = 'CLARK') 
      and 
      sal < (select sal from emp where ename = 'CLARK')
-- 查询职务和SCOTT相同,比SCOTT雇佣时间早的雇员信息  
select * 
from emp
where job = (select job from emp where ename = 'SCOTT') 
      and 
      hiredate < (select hiredate from emp where ename = 'SCOTT')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 多行子查询
-- 多行子查询:
-- 【1】查询【部门20中职务同部门10的雇员一样的】雇员信息。
-- 查询雇员信息
select * from emp;
-- 查询部门20中的雇员信息
select * from emp where deptno = 20;-- CLERK,MANAGER,ANALYST
-- 部门10的雇员的职务:
select job from emp where deptno = 10; -- MANAGER,PRESIDENT,CLERK
-- 查询部门20中职务同部门10的雇员一样的雇员信息。
select * from emp 
where deptno = 20 
and job in (select job from emp where deptno = 10)
-- > Subquery returns more than 1 row
select * from emp 
where deptno = 20 
and job = any(select job from emp where deptno = 10)
-- 【2】查询工资比所有的“SALESMAN”都高的雇员的编号、名字和工资。
-- 查询雇员的编号、名字和工资
select empno,ename,sal from emp
-- “SALESMAN”的工资:
select sal from emp where job = 'SALESMAN'
-- 查询工资比所有的“SALESMAN”都高的雇员的编号、名字和工资。
-- 多行子查询:
select empno,ename,sal 
from emp 
where sal > all(select sal from emp where job = 'SALESMAN');
-- 单行子查询:
select empno,ename,sal 
from emp 
where sal > (select max(sal) from emp where job = 'SALESMAN');
-- 【3】查询工资低于任意一个“CLERK”的工资的雇员信息。  
-- 查询雇员信息
select * from emp;
-- 查询工资低于任意一个“CLERK”的工资的雇员信息
select * 
from emp
where sal < any(select sal from emp where job = 'CLERK')
and job != 'CLERK'
-- 单行子查询:
select * 
from emp
where sal < (select max(sal) from emp where job = 'CLERK')
and job != 'CLERK'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
5.1.8.2 相关子查询
  • 不相关的子查询:子查询可以独立运行,先运行子查询,再运行外查询。
  • 相关子查询:子查询不可以独立运行,并且先运行外查询,再运行子查询
    1. 好处:简单 功能强大(一些使用不相关子查询不能实现或者实现繁琐的子查询,可以使用相关子查询实现)
    2. 缺点:稍难理解
-- 【1】查询最高工资的员工  (不相关子查询)
select * from emp where sal = (select max(sal) from emp)
-- 【2】查询本部门最高工资的员工   (相关子查询)
-- 方法1:通过不相关子查询实现:
select * from emp where deptno = 10 and sal = (select max(sal) from emp where deptno = 10)
union
select * from emp where deptno = 20 and sal = (select max(sal) from emp where deptno = 20)
union
select * from emp where deptno = 30 and sal = (select max(sal) from emp where deptno = 30)
-- 缺点:语句比较多,具体到底有多少个部分未知
-- 方法2: 相关子查询
select * from emp e where sal = (select max(sal) from emp where deptno = e.deptno) order by deptno
-- 【3】查询工资高于其所在岗位的平均工资的那些员工  (相关子查询)
-- 不相关子查询:
select * from emp where job = 'CLERK' and sal >= (select avg(sal) from emp where job = 'CLERK')
union ......
-- 相关子查询:
select * from emp e where sal >= (select avg(sal) from emp e2 where e2.job = e.job)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

5.2 DML数据操作语言

  • DML主要用于对数据库中的数据进行增加、修改和删除的操作

5.2.1 INSERT:增加数据

-- INSERT INTO 语句用于向表格中插入新的行。
INSERT INTO 表名称 VALUES (1,2,....);
-- 我们也可以指定所要插入数据的列:
INSERT INTO table_name (1,2,...) VALUES (1,2,....);
  • 1
  • 2
  • 3
  • 4

5.2.2 UPDATE:增加数据

-- Update 语句用于修改表中的数据。
UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值;
-- 更新某一行中的若干列
UPDATE 表名称 SET 列名称 = 新值,列名称 = 新值,... WHERE 列名称 = 某值;
  • 1
  • 2
  • 3
  • 4

5.2.3 DELETE:删除数据

-- DELETE 语句用于删除表中的行
DELETE FROM 表名称 WHERE 列名称 =;
-- 可以在不删除表的情况下删除所有的行。这意味着表的结构、属性和索引都是完整的:
DELETE FROM table_name;
  • 1
  • 2
  • 3
  • 4

5.3 DDL数据定义语言

  • DDL主要用针对是数据库对象(数据库、表、索引、视图、触发器、存储过程、函数)进行创建、修改和删除操作。其主要包括:

5.3.1 CREATE:创建数据库对象

CREATE TABLE 表名称
(
列名称1 数据类型,
列名称2 数据类型,
列名称3 数据类型,
....
);
-- 查看建表语句
show create table 表名称; 
-- 快速添加一张表
create table t_student2
as
select * from t_student;
-- 快速添加,结构跟t_student一致,数据没有:
create table t_student3
as
select * from t_student where 1=2;
select * from t_student3;
-- 快速添加:只要部分列,部分数据:
create table t_student4
as
select sno,sname,age from t_student where sno = 2;
select * from t_student4;
-- 删除数据操作 :清空数据
delete from t_student;
truncate table t_student;
/*
delete和truncate的区别:
从最终的结果来看,虽然使用TRUNCATE操作和使用DELETE操作都可以删除表中的全部记录,但是两者还是有很多区别的,其区别主要体现在以下几个方面:
(1)DELETE为数据操作语言DML;TRUNCATE为数据定义语言DDL。
(2) DELETE操作是将表中所有记录一条一条删除直到删除完;TRUNCATE操作则是保留了表的结构,重新创建了这个表,所有的状态都相当于新表。因此,TRUNCATE操作的效率更高。
(3)DELETE操作可以回滚;TRUNCATE操作会导致隐式提交,因此不能回滚(在第十章中会讲解事务的提交和回滚)。
(4)DELETE操作执行成功后会返回已删除的行数(如删除4行记录,则会显示“Affected rows:4”);截断操作不会返回已删除的行量,结果通常是“Affected rows:0”。DELETE操作删除表中记录后,再次向表中添加新记录时,对于设置有自增约束字段的值会从删除前表中该字段的最大值加1开始自增;TRUNCATE操作则会重新从1开始自增。
*/

-- 创建约束
create table t_student(
        sno int(6) auto_increment, 
        sname varchar(5) not null, 
        sex char(1) default '男',
        age int(3),
        enterdate date,
        classname varchar(10),
        email varchar(15),
        constraint pk_stu primary key (sno),  -- pk_stu 主键约束的名字
        constraint ck_stu_sex check (sex = '男' || sex = '女'),
        constraint ck_stu_age check (age >= 18 and age <= 50),
        constraint uq_stu_email unique (email)
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

5.3.2 ALTER:修改数据库对象

-- 修改表结构
alter table t_student add score double(5,2) ; -- 5:总位数  2:小数位数
-- 增加一列(放在最前面)
alter table t_student add score double(5,2) first;
-- 增加一列(放在sex列的后面)
alter table t_student add score double(5,2) after sex;
-- 删除一列:
alter table t_student drop score;

-- 修改一列:
alter table t_student modify score float(4,1); -- modify修改是列的类型的定义,但是不会改变列的名字
alter table t_student change score score1 double(5,1); -- change修改列名和列的类型的定义

-- 在创建表以后添加约束:
alter table t_student add constraint pk_stu primary key (sno) ; -- 主键约束
alter table t_student modify sno int(6) auto_increment; -- 修改自增条件
alter table t_student add constraint ck_stu_sex check (sex = '男' || sex = '女');
alter table t_student add constraint ck_stu_age check (age >= 18 and age <= 50);
alter table t_student add constraint uq_stu_email unique (email);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

5.3.3 DROP:删除数据库对象

-- 删除表:
drop table 表名称;
  • 1
  • 2

5.3.4 DESC查看表结构

-- 查看表结构
desc 表名;
  • 1
  • 2

5.4 DCL数据控制语言

  • DCL用来授予或回收访问 数据库的权限,其主要包括:

5.4.1 GRANT:授予用户某种权限

5.4.2 REVOKE:回收授予的某种权限

5.5 TCL事务控制语言

  • TCL用于数据库的事务管理。其主要包括:
    1. START TRANSACTION:开启事务
    2. COMMIT:提交事务
    3. ROLLBACK:回滚事务
    4. SET TRANSACTION:设置事务的属性

5.5.1 事务

  • 事务及其特征:事务(Transaction)是用来维护数据库完整性的,它能够保证一系列的MySQL操作要么全部执行,要么全不执行。
  • 事务的概念:事务(Transaction)指的是一个操作序列,该操作序列中的多个操作要么都做,要么都不做,是一个不可分割的工作单位,是数据库环境中的逻辑工作单位,由DBMS(数据库管理系统)中的事务管理子系统负责事务的处理。目前常用的存储引擎有InnoDB(MySQL5.5以后默认的存储引擎)和MyISAM(MySQL5.5之前默认的存储引擎),其中InnoDB支持事务处理机制,而MyISAM不支持。
  • 事务的特性:事务处理可以确保除非事务性序列内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的序列,可以简化错误恢复并使应用程序更加可靠。但并不是所有的操作序列都可以称为事务,这是因为一个操作序列要成为事务,必须满足事务的原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。这四个特性简称为ACID特性。
    1. 原子性:原子是自然界最小的颗粒,具有不可再分的特性。事务中的所有操作可以看做一个原子,事务是应用中不可再分的最小的逻辑执行体。使用事务对数据进行修改的操作序列,要么全部执行,要么全不执行。通常,某个事务中的操作都具有共同的目标,并且是相互依赖的。如果数据库系统只执行这些操作中的一部分,则可能会破坏事务的总体目标,而原子性消除了系统只处理部分操作的可能性。
    2. 一致性是指事务执行的结果必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库中只包含事务成功提交的结果时,数据库处于一致性状态。一致性是通过原子性来保证的。
      例如:在转账时,只有保证转出和转入的金额一致才能构成事务。也就是说事务发生前和发生后,数据的总额依然匹配。
    3. 隔离性:隔离性是指各个事务的执行互不干扰,任意一个事务的内部操作对其他并发的事务,都是隔离的。也就是说:并发执行的事务之间既不能看到对方的中间状态,也不能相互影响。
      例如:在转账时,只有当A账户中的转出和B账户中转入操作都执行成功后才能看到A账户中的金额减少以及B账户中的金额增多。并且其他的事务对于转账操作的事务是不能产生任何影响的。
    4. 持久性:持久性指事务一旦提交,对数据所做的任何改变,都要记录到永久存储器中,通常是保存进物理数据库,即使数据库出现故障,提交的数据也应该能够恢复。但如果是由于外部原因导致的数据库故障,如硬盘被损坏,那么之前提交的数据则有可能会丢失。
-- 创建账户表:
create table account(
        id int primary key auto_increment,
        uname varchar(10) not null,
        balance double
);
-- 查看账户表:
select * from account;
-- 在表中插入数据:
insert into account values (null,'丽丽',2000),(null,'小刚',2000);
-- 丽丽给小刚 转200元:
update account set balance = balance - 200 where id = 1;
update account set balance = balance + 200 where id = 2;
-- 默认一个DML语句是一个事务,所以上面的操作执行了2个事务。
update account set balance = balance - 200 where id = 1;
update account set balance = balance2 + 200 where id = 2;
-- 必须让上面的两个操作控制在一个事务中:
-- 手动开启事务:
start transaction;
update account set balance = balance - 200 where id = 1;
update account set balance = balance + 200 where id = 2;
-- 手动回滚:刚才执行的操作全部取消:
rollback;
-- 手动提交:
commit;
-- 在回滚和提交之前,数据库中的数据都是操作的缓存中的数据,而不是数据库的真实数据
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 事务并发问题:
  1. 脏读(Dirty read):当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

在这里插入图片描述

  1. 不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
    在这里插入图片描述
  2. 幻读 (Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
    在这里插入图片描述
  3. 不可重复度和幻读区别:不可重复读的重点是修改,幻读的重点在于新增或者删除。
  4. 解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
  • 事务的隔离级别用于决定如何控制并发用户读写数据的操作。数据库是允许多用户并发访问的,如果多个用户同时开启事务并对同一数据进行读写操作的话,有可能会出现脏读、不可重复读和幻读问题,所以MySQL中提供了四种隔离级别来解决上述问题。
    在这里插入图片描述
-- 查看默认的事务隔离级别  MySQL默认的是repeatable read  
select @@transaction_isolation;  
-- 设置事务的隔离级别   (设置当前会话的隔离级别)
set session transaction isolation level read uncommitted;  
set session transaction isolation level read committed;  
set session transaction isolation level repeatable read;  
set session transaction isolation level serializable;  
start transaction ;
select * from account where id = 1;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

5.5.2 视图

  1. 视图的概念:视图(view)是一个从单张或多张基础数据表或其他视图中构建出来的虚拟表。同基础表一样,视图中也包含了一系列带有名称的列和行数据,但是数据库中只是存放视图的定义,也就是动态检索数据的查询语句,而并不存放视图中的数据,这些数据依旧存放于构建视图的基础表中,只有当用户使用视图时才去数据库请求相对应的数据,即视图中的数据是在引用视图时动态生成的。因此视图中的数据依赖于构建视图的基础表,如果基本表中的数据发生了变化,视图中相应的数据也会跟着改变。
  2. 视图的好处:简化用户操作:视图可以使用户将注意力集中在所关心地数据上,而不需要关心数据表的结构、与其他表的关联条件以及查询条件等。对机密数据提供安全保护:有了视图,就可以在设计数据库应用系统时,对不同的用户定义不同的视图,避免机密数据(如,敏感字段“salary”)出现在不应该看到这些数据的用户视图上。这样视图就自动提供了对机密数据的安全保护功能
-- 创建/替换单表视图:
create or replace view myview01
as
select empno,ename,job,deptno 
from emp
where deptno = 20
with check option;
-- 查看视图:
select * from myview01;
-- 在视图中插入数据:
insert into myview01 (empno,ename,job,deptno) values (9999,'lili','CLERK',20);
insert into myview01 (empno,ename,job,deptno) values (8888,'nana','CLERK',30);
insert into myview01 (empno,ename,job,deptno) values (7777,'feifei','CLERK',30); 
-- > 1369 - CHECK OPTION failed 'mytestdb.myview01'
-- 创建/替换多表视图:
create or replace view myview02
as 
select e.empno,e.ename,e.sal,d.deptno,d.dname
from emp e
join dept d
on e.deptno = d.deptno
where sal > 2000 ;
select * from myview02;
-- 创建统计视图:
create or replace view myview03
as
select e.deptno,d.dname,avg(sal),min(sal),count(1)
from emp e
join dept d
using(deptno)
group by e.deptno ;
select * from myview03;
-- 创建基于视图的视图:
create or replace view myview04
as
select * from myview03 where deptno = 20;
select * from myview04;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

5.5.3 存储过程

  • 概念:存储过程(Stored Procedure)就是数据库中保存(Stored)的一系列SQL命令(Procedure)的集合。也可以将其看作相互之间有关系的SQL命令组织在一起形成的一个小程序
  • 存储过程的优点
    1. 提高执行性能。存储过程执行效率之所高,在于普通的SQL语句,每次都会对语法分析,编译,执行,而存储过程只是在第一次执行语法分析,编译,执行,以后都是对结果进行调用。
    2. 可减轻网络负担。使用存储过程,复杂的数据库操作也可以在数据库服务器中完成。只需要从客户端(或应用程序)传递给数据库必要的参数就行,比起需要多次传递SQL命令本身,这大大减轻了网络负担。
    3. 可将数据库的处理黑匣子化。应用程序中完全不用考虑存储过程的内部详细处理,只需要知道调用哪个存储过程就可以了
-- 定义一个没有返回值 存储过程
-- 实现:模糊查询操作:
select * from emp where ename like '%A%';
create procedure mypro01(name varchar(10))
begin
        if name is null or name = "" then
                select * from emp;
        else
    select * from emp where ename like concat('%',name,'%');
        end if;	
end;
-- 删除存储过程:
drop procedure mypro01;
-- 调用存储过程:
call mypro01(null);
call mypro01('R');
-- 定义一个  有返回值的存储过程:
-- 实现:模糊查询操作:
-- in 参数前面的in可以省略不写
-- found_rows()mysql中定义的一个函数,作用返回查询结果的条数
create procedure mypro02(in name varchar(10),out num int(3))
begin
        if name is null or name = "" then
                select * from emp;
        else
    select * from emp where ename like concat('%',name,'%');
        end if;	
        select found_rows() into num;
end;
-- -- 调用存储过程:
call mypro02(null,@num);
select @num;
call mypro02('R',@aaa);
select @aaa;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/619264
推荐阅读
相关标签
  

闽ICP备14008679号