学堂在线笔记
- 前端与后台的故事——SQL语言及其编程
- 第一讲:数据会说话
- 第三讲:数据库的约束机制
- 第四讲——表单查询
- 第五讲——常用数学函数
- 第六讲——表单的条件查询
- 第七讲——常用字符串函数
- 第八讲——表单统计查询及过滤排序
- 第九讲——常用日期时间函数
- 第十讲——标准select语句执行顺序
- 第十一讲——内连接/联接查询
- 第十二讲——不一样的流程控制函数
- 第十三讲——外连接查询
- 第14讲——特有的系统函数
- 第15讲——连接查询语句的执行顺序
- 第16讲——常用嵌套查询
- 第17讲——嵌套查询语句执行顺序
- 第18讲——视图及其应用
- 第十九讲——数据插入
- 第20讲——数据删除
- 第21讲——数据修改
- 第22讲——“增删改”有风险
- 第23讲——IN型参数存储过程编程
- 第23讲——OUT型参数存储过程编程
- 第25讲——INOUT型参数存储过程编程
- 第26讲——通过触发器进行数据更新
- 第27讲——PHP与MySQL
前端与后台的故事——SQL语言及其编程
第一讲:数据会说话
数据(data):是数据库中存储的基本对象,是用来描述事物的符号记录。
.eg.
数字、文字、图形、图像、音频、视频、学生信息记录、订单信息记录等。
数据的含义:又称为数据的语义,数据与其语义不可分割。在不同环境中,同一个数据会有不同的语义。
数据库(DataBase,简称DB):是长期存储在计算机内,有组织、可共享的大量数据的集合。
数据库管理系统(Database Management System,简称DBMS):是为了科学地组织和存储数据、高效地获取和维护数据而开发的专门软件,是一种位于用户应用与操作系统之间的大型而复杂的软件系统。
数据库系统层次示意图:
数据库管理系统:
数据库管理系统的主要功能:
- 数据定义功能:用来定义数据库中的数据对象。
- 数据操纵功能:提供数据操纵语言,实现对数据库中数据的增、删、改、查等基本操作。
- 数据组织、存储和管理功能:用来实现数据的组织、存储和管理,实现数据之间的联系,提高数据的存储效率。
- 事务管理和运行管理:用来实现数据的安全性、完整性、并发性,以及发生故障后数据库的恢复等等。
- 其他功能:包括异构数据库之间的互访以及互操作,不同的DBMS之间的数据传输等等。
数据库系统(DataBase System,简称DBS):是指在计算机系统中引入数据库后的系统构成。里面包括:数据库(DB)、数据库管理系统(DBMS)、及其应用开发工具和应用程序(APP)、数据库管理员(DBA)。
show datebases; :显示本MySQL服务器上所以数据库名称
第三讲:数据库的约束机制
数据世界:现实世界的信息在机器世界中以数据形式存储在数据库中,被我们称作数据世界。
现实世界:是指存在于人民头脑之外的客观世界,也称为现实世界。
主键约束(PRIMARY KEY):具有包含唯一标识数据表中每一行的值所在的一列或一组列成为表的主键(PK),用于强制表的实体完整性。在数据库表中往往将编号、学号、序号等列设为主键。
起到了强制表的实体完整性作用,也就是用来区别表中每一行数据记录。如果对多列组合定义了主键约束,则该多列组合中的一列中的值可能会重复,但来自主键约束定义中所有列的值的任意组合必须唯一。
注意事项:
- 每一个表只能定义一个主键
- 唯一性原则:主键值必须唯一标识表中的每一行,且不能为空值,及表中不可能存在两行数据具有相同的主键值。
- 最小化原则:复合主键不能包含不必要的多余序列,当把复合主键的某一列删除后,如果剩下的列构成的主键仍然满足唯一性原则,那么这个复合主键是不正确的。
外键约束(FOREIGN KEY):用来在两个表的数据之间建立关联,它可以是一列或者多列,一个表可以有一个或者多个外键。
外键强制的是参照完整性,及一个表的外键可以是空值,如果不是空值,则每一个外键的值必须等于另一个表中的主键的某一个值,所以外键往往是建立在有关系的两个表之间的。
主表(父表):对于两个具有关联关系的表而言,相关联字段中主键所在的表就是主表。
外表(子表):对于两个具有关联关系的表而言,相关联字段中外键所在的表就是外表。
定义一个外键时,需要遵守下列规则:
- 主表必须已经存在于数据库中,或者是当前正在创建的表,如果是后一种情况,则主表与外表是同一个表,这样的表称为自参照表,这种结构称为自参照完整性。
- 必须为主表定义主键。
- 主键不能包含空值,但允许在外键中出现空值,只要外键的每个非空值出现在指定的主键中,这个外键的内容就是正确的。
- 外键中列的数目必须和主表的主键中列的数目相同。
- 外键中列的数据类型必须和主表中对相应列的数据类型相同。
- 对于数据库中定义的外键,如果不在需要,可以将其删除,但是外键一旦删除,就会解除主表和外表之间的关联关系。
非空约束(NOT NULL):强制字段的值不能为空。
唯一约束(Unique Key):强制某列中的值具有唯一性,允许为空,但只能出现一个空值。唯一约束可以看作是主键约束的有效补充,一个表可以定义多个唯一约束。
默认约束(DEFAULT):用来指定数据表中某列的默认值如果向数据表插入一条新的记录时没有为该字段赋值,那么系统会自动为这个字段赋默认值。
默认约束常常用在某列中数据存储大量重复的情况,比如性别、国籍、民族等。
第四讲——表单查询
SQL语言:是结构化查询语言(Student Query Language)的简称,SQL语言是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统。
SQL语言集数据定义DDL、数据操纵语言DML和数据控制语言DCL于一体,可以完成数据库中的全部工作。
数据定义DDL:数据库、数据表等数据对象的创建、修改或删除等数据对象的创建、修改或删除等操作命令。
数据控制DCL:数据库、数据表等数据对象的访问允许、禁止等安全控制操作命令。
数据操纵DML:数据表中数据的增、删、改、查操作命令。
数据定义DDL:
- create —— 创建对象
- drop —— 删除对象
- alter —— 修改对象
数据操纵DML:
- grant —— 授权
- revoke —— 回收权限
数据控制DCL:
- insert —— 新增数据
- update —— 修改数据
- delete —— 删除数据
- select —— 查询数据
单表查询:
查询语句的结构最简单,单表查询仅由两个子句构成,所谓单表是指仅向数据库内一个表进行查询。一个数据库往往是由若干个数据表组成,在实际的应用环境中甚至多达上百个数据表,而单表查询则仅从某一个数据表中来查找用户所需的数据。
语法结果如下:
Select 字段列表 [字段别名] /*
From 数据源;
[]:这里的内容可以有,也可以省略,即为可选项
/:二者选其一
Select语句是查询语句的命令动词,表示在这里进行的是查询操作,SQL语句所有的关键词都不区分大小写。From用来指定查询的数据所来自的数据源,也就是数据库中的数据表或者视图。
.eg.查询所有学生的信息:
select * from stuinfo;
select stname,sex from stuinfo;(假设stuinfo中只有stname和sex两列)
Select和from与其他标识符之间至少需间隔一个空格。
*表示按照create table 创建表顺序排列的所有列。
在实践应用中,不建议使用Select * ,因为这会降低数据查询效率。
在任何计算机语言的语法中,标点符号都必须是英文符号。
.eg.
- 列的别名语法上可以用一对单引号引用起来,也可以没有单引号,但如果别名内部有空格,则必须要用单引号进行引用
- 列名和列的别名之间可以用空格隔开
- 列名和列的别名之间也可以用AS来连接
- 列的顺序无关紧要,与表中的列的物理顺序并没有关系,只需满足用户的查询需求即可。
- 列名不区分大小写,但在实际的应用中,往往需要遵守一定的命名规则,以提高脚本的可读性,这是一种良好的编程习惯。
- 列名之间必须用英文逗号隔开,但是最后一个列名后面不需要标点符号。
- Timestampdiff这个函数是mysql众多常用函数中的一个,利用函数可以方便的实现很多计算或者特殊功能。
- 查询语句中的计算列一般建议设置合适的别名。
语法说明:
最基本的select语句语法:
Select [All / Distinct] 需要查询的表列/计算列
From 表/视图
- *在Select子句中代表的是所有列,不过为了提高查询效率,在实际应用中不建议使用。
- Distinct用来过滤掉查询结果集中的重复行,与之对应默认为all,也就是Select默认为Select All。
- 用Select查询不仅可以查询数据中原始的数据,而且可以查询计算的值。
- 可以对查询结果集的列重新命名,这样可以让结果集可读性更强。
第五讲——常用数学函数
mysql作为DBMS存储和管理着大量数据,其中数值数据不可或缺。
数值类型:
主要用来存储数字,包括整数、实数等。
MySQL数值类型常用的主要分为:整数类型、实数类型(定点数类型、浮点数类型)。
(1)整数类型:计算机中存储任何数据都是有限的存储空间。为了能存储较大范围的整数,同时提高存储空间利用率,每一种程序设计语言,都会设计多种整数类型。
注意:
- 每种数据类型都有相应的类型名称,这些名称就是MySQL的关键字,不区分大小写:另外,INTEGER同INT类型。
- 在实践应用中,根据应用场景需要作出合理选择。比如用来记录某人年龄的话,用无符号TINYINT
(2)定点数类型:用于保存必须为确切精度的数值,主要有DECIMAL和NUMERIC类型。
DECIMAL(M,D):
M表示十进制数字总的个数,默认取值为10,取值范围为1~65,取值0时会被设为默认值,超出范围会报错。
D表示小数点后面数字的位数,默认取值为0,取值范围为0~30,而且必须<=M,超出范围会报错。
如DECIMAL(5,2):取值范围为-999.99~999.99
注意:
- 创建数据表时,某字段定义为DECIMAL类型且不带任何参数,等同于DECIMAL(10,0)。
- DECIMAL(M,D)带一个参数时,D取默认值,也就是0。
- 对于DECIMAL(M,D),当M取65,D取0时,取得这个数据类型的最大和最小值。
- 实数值比较准确,推荐使用定点数数据类型。
(3)浮点数类型:
常见类型:
FLOAT单精度浮点数和DOUBLE双精度浮点数。
定义方式:
FLOAT(M,D),DOUBLE(M,D),M和D的含义与定点数一样为0,这里的M和D与定点数一样,默认值均为0。
长度一定下:
表示数据范围大的特点,也存在误差问题。
内存中:
FLOAT占4-byte,DOUBLE占8-byte。
注意:
- M取值范围为0-255,因为FLOAT只保证6位有效数字的准确性,在FLOAT(M,D)中,M<=6时,数字通常是准确的。
- D取值范围为0-30,同时必须**<=M**,因为DOUBLE只保证16位有效数字的准确性,在DOUBLE(M,D)中,M<=16时,数字通常是准确的。
- 浮点数是不准确的,所以在实践应用中我们要避免使用**“=”**来判断两个数是否相等。
常用函数
(1)format(n,d):数值格式化函数
功能:将数值n,保留d位小数,并且整数部分用逗号分隔千分位,小数部分进行四舍五入。
注意:数据经过千分位隔离后,会变成字符串,能够给阅读提供比较好的体验,但在计算上却会造成很大的困扰。所以如果只是保留小数,不建议使用这个函数。
(2)round(n,d):四舍五入函数
功能:返回n的四舍五入值,保留d位小数(d的默认值为0),函数不会将数值n变成字符串类型。
(3)ceil(n)进一取整函数,floor(n)舍一取值函数
功能:对数值n进行统一进一及统一舍一的取证操作
(4)truncate(n,d)数值截取函数
功能:不进行四舍五入,直接保留数字n的d位小数。
(5)rand(n)随机数函数
功能:返回范围0到1.0内的随机浮点值(可以使用数字a作为初始值)
(6)sign(n)符号函数
功能:返回参数符号(为-1代表负数,0或1代表正数)
(7)mod(n,m)取模函数
功能:取模函数,返回n被m除的余数(同%操作符)
(8)least(x,y,…):最小值函数
功能:返回参数列表中的最小值,计算规则如下:
- 返回值被使用在一个INTEGER上下文,或所有的参数都是整数值,他们作为正数比较。
- 如果返回值被使用在一个REAL上下文,或所有的参数是实数值,他们作为实数比较。
- 任何参数是一个大小敏感的字符串,参数作为大小写敏感的字符串被比较。
(9)greatest(x,y,…)最大值函数
功能:返回参数列表中的最大值,计算规则同least(x,y,…)
(10)pi():圆周率函数
功能:返回圆周率
应用提醒:
调用无参函数的时候不需要提供参数,函数名pi后面是一对空的括号,不像前面的函数,在调用时括号里都提供了一个参数,MySQL还有很多这样的无参函数,调用时必须注意,空括号必须保留,不能去掉,否则报错。
(11)degrees(n)/radians:角度弧度转换函数
功能:把n从弧度变换为角度/把n从角度变换为弧度。
(12)三角函数:
(13)其他常用的数学计算函数:
abs(n):返回n的绝对值
exp(n):返回值e的n次方
log(n):返回n的自然对数
log10(n):返回n以10为底的对数
pow(x,y):返回值x的y次幂
sqrt(n):返回非负数n的平方根
应用提醒:
数学函数都是MySQL自带的内置函数,只要正确调用就可以,所有函数的名称不区分大小写,参数的个数和类型必须符合系统要求,否则报错。
第六讲——表单的条件查询
SELECT 字段列表[字段别名]/*
FROM 数据源
WHERE 条件
(1)条件查询语法
应用提醒:
- Select语句由多个子句构成,可以写在一行,也可分行。
- WHERE子句的核心是合理的行筛选条件表达式。
- MySQL的日期类型很丰富,其中DATE类型格式为"YYYY-MM-DD"
查询语句的WHERE子句,筛选条件很丰富。
在SQL语句中,所有字符常量必须用单引号引起来,否则,条件对比出错。
MySQL支持模糊查找。
应用提醒:
- Like是一种模糊比较运算符,仅能用于字符类型比较。
- %即通配符,可以理解为占位符,一个%可以代表0-N个任意字符。李%指以李字开头的任意一串字符。
常用通配符:
%:用来表示任意多个字符,包含0-N个字符
_:用来表示任意单个字符,如’李_'就代表‘李’姓且单名
escape:用来表示转义特定字符,比如要查找的字符串中包含%或自身
应用提醒:
- IN包含运算,用于判断某个值是否属于某个集合中。
- NOT IN,表示不包含运算,是IN运算的反运算。
- 由IN形成的条件也可以变换成若干个用OR连接起来的比较条件。
.eg.:
SELECT stuname,sex,class
FROM stuinfo
WHERE BirthPlace='西藏' AND BirthPlace='新疆'
应用提醒:
- NULL的空值,不代表0,空格或空字符串等
- IS NULL,是专门用于判断空值NULL的运算,不能用“=NULL”来取代
- ISNULL(),是用于判断空值的函数
- IS NOT NULL用于判断非空值
应用提醒
- 在实际应用场景,查询的筛选条件往往比较复杂。
- AND(与)优先级高于OR(或)运算,可以使用括号来调整运算符的优先级。
本章小结:
关系比较:
=、<=>、<>、{!=}、<、<=、>、>=,其中=、<=>几乎相同
模糊匹配(模糊查找):
like、not like以及三个常用的适配符%、_、escape
确定集合:
in、not in
空值判断:
is null、is not null,NULL不区分大小写,也不需要单引号、括号等定界符
逻辑运算符:
NOT或者!,AND或者&&,OR或者||,XOR(异或)
确定范围:
between、and、not between and,用于进行数值闭区间判断。
第七讲——常用字符串函数
MySQL中最常用的字符类型:
char、varchar、text
(1)char类型:
char(n)用于存储长度为n的定长字符串,n的取值范围为0~255之间。
应用提醒:
- 字符串常量在SQL语句中需要用英文的单引号作为定界符,否则报错。
- 定长字符类型的应用场景中的数据的共同特点就是长度固定,最适合定义为char类型。
- 定长类型虽然在实践应用中存在一定的空间浪费,但却在效率上有优势。
(2)varchar类型
varchar(n)用于存储最大长度为n的可变长字符串。varchar的长度类型支持65535。
应用提醒:
- 字符类型到底能存放多少字符,与字符编码有关,常用的字符编码有GBK(每个字符最多占2个字节,最大长度不能超过32766)、UTF8(每个字符最多占3个字节,最大长度不能超过21845)
- MySQL5.0版本以上,以varchar(20)为例,可存放20个字符,最大大小是65532字节
- 若定义数据表的字段时超过上述限制,则varchar字段会被强行转为text类型,并产生warning。
- 导致实际应用中varchar长度限制的还有定义的长度
- varchar在一般情况下存储都够用
(3)text类型:
text类型是非二进制类型字符串,只能存储纯文本,其值是大小写不敏感的
应用提醒:
- 经常变化的字段用varchar
- 固定长度的用char
- 尽量使用varchar,超过255字符的只能使用varchar或者text
- 能用varchar的地方不用text
- 效率是char>varchar>text
应用提醒:
调用函数时,请确保函数名正确,参数匹配,否则调用失败。在实践应用中,建议查询MySQL函数的用户手册,那里更全面。
第八讲——表单统计查询及过滤排序
统计查询
SELECT 字段列表[字段别名]/*
FROM 数据源
[WHERE 行筛选条件]
[GROUP BY 分组依据] //用来控制对数据的分组
[HVAING 过滤条件]
[ORDER BY 排序条件]
聚合统计函数,也叫里函数,常用的有:
(1)Count([distinct]col):参数col代表列名,默认是distinct缺省,重复值复计数;如果用distinct限定,则重复值只计一次数。
(2)Max([distinct]col):返回指定列的最大值,distinct的作用还是去重复。
(3)Min([distinct]col):返回指定列的最小值。
(4)Sum([distinct]col):返回指3定列的所有值之和,当然重复值是否重复计算取决于distinct,显然指定列只有数值类型才有意义。
(5)Avg([distinct]col):返回指定列的所有值之平均值,同sum一样指定列应该是数值类型。
应用提醒:
- COUNT( * )和COUNT(stuno)或者COUNT(stuname)统计结果都是一样的,这也唯一一处建议使用 * 号来表示一行的地方。
- COUNT(列名)在统计时,如果列中有NULL值,NULL不作计数统计
- 这个任务中没有group by子句,统计时将数据源中的所有记录当成一组进行统计
应用提醒:
- GROUP子句控制系统首先将数据源stuinfo表中所有行,按照studept所在分院列进行分组
- 分组后,count()和avg()函数统计就按两组分别统计,这也就是常说的“分组统计”
- 聚合统计的SELECT子句中的字段列表有限制
应用提醒:
- GROUP子句,在实践应用中可以有更多级分组
- 首先按teadept教师所在学院分组
- 再按TitleLevel职称等级进行了二级分组
应用提醒:
GROUP BY TitleLevel,teadept中多级分组字段的顺序是有关的,这类似于EXCEL中的多级分类汇总
应用提醒:
- from子句首先执行,而后便是where、聚合函数、having依次执行HAVING 过滤是对where筛选的有效补充。
- 应用中 where子句条件筛选优先于having子句
where和having子句有各自的应用场景,且where子句优先于having子句,也就是说,如果WHERE子句能控制的行筛选,就不要用HAVING子句
第九讲——常用日期时间函数
(1)日期时间类型
MySQL中表示日期时间值的类型分为:DATETIME、DATE、TIMESTAMP、TIME和YEAR。每个日期时间类型都固定的存储字节数、有效值范围和一个“零”值。
year占1个字节,范围为1901~ 2155,time占3个字节,范围为-838:59:59 ~838:59:59
相同点:两者都可用来表示YYYY-MM-DD HH:MM:SS 类型的日期。
不同点:他们的的存储方式,大小(字节),表示的范围不同。
在建表时,TIMESTAMP可以为日期设置一个默认值,而DATATIME不行。在更新表时,TIMESTAMP可以设置为自动更新时间为当前时间,而TIMESTAMP它把客户端插入的时间从当前时区转化为UTC,也就是世界标准时间进行存储,查询时将其又转化为客户端当前时区进行返回。而DATETIME不做任何改变,也就是原样输入和输出。
应用提醒:
TIMESTAMP和DATETIME都可用来表示YYYY-MM-DD HH:MM:SS类型的日期, 除了存储方式和存储范围以及大小不一样,没有太大区别。如果记录的日期需要让不同时区的人使用,最好使用TIMESTAMP。
(2)日期时间函数
数据库中会存放大量的日期时间数据,而日期时间的计算不同于普通数值运算,DBMS(数据库管理系统)会提供大量的函数,MySQL也一样。
应用提醒:
- CURDATE(),CURTIME():分别获取当前系统时间里的日期和时间值。
- NOW(),SYSDATE():获取系统当前的日期时间值,NOW()函数取的是语句开始执行的时间,而SYSDATE()取的是语句执行过程中动态的实时时间。
- SLEEP(3)是让系统休眠3秒,也是mysql的自带函数。
应用提醒:
MONTH(),MONTHNAME()对日期类型进行处理,MONTH()返回数值,,MONTHNAME()返回字符串。
应用提醒:
- TIMESTAMPDIFF(YEAR,birth,CURDATE())常用于根据出生日期来计算年龄的情况,第一参数year说明返回的结果单位为年
- 函数嵌套调用,即在TIMESTAMPDIFF(YEAR,birth,CURDATE())第三个参数本身也是函数,用于获取系统当前日期,出生日期和当前日期之间间隔的年值,正是年龄
应用提醒:
- YEAR(CURDATE())-YEAR(birth)也可以获取年龄,是用YEAR函数当前日期和出生日期的年,然后进行减法运算,获取两个年度之间间隔的年数。
- 该例中特意将两种方法计算的年龄列,AGE1和AGE2都保留在结果集中,以便对比,对比两种方法计算的年龄,TIMESTAMPDIFF()函数更准确。AGE1和AGE2并不完全相同,真正年龄的计算并不只是与年有关,根据出生日期来计算更准确,用TIMESTAMPDIFF()。
应用提醒:
- DATE_ADD(NOW(),INTERVAL1 MONTH) 获取当前日期后一个月的日期,函数INTERVAL是关键字,MONTH是进行日期推算的单位。
- DATE_SUB(NOW(),INTERVAL1 MONTH)正好与DATE_ADD()函数相反,获取当前日期前一个月的日期,函数参数设置是一样的。
- 通过这些函数可实现查询前/后一个月在微信或支付宝的账单日期控制。
第十讲——标准select语句执行顺序
计算机程序设计语言:分四代
(1)第1代机器语言:由二进制0和1代码指令构成,不同的CPU 具有不同的指令系统。机器语言程序具有难编写、难修改、难维护的特点,需要用户直接对存储空间进行分配,编程效率极低。
(2)第2代汇编语言:是机器指令的符号化,与机器指令存在着直接的对应关系,所以汇编语言同样存在着难学难用、容易出错、维护困难等缺点。但是汇编语言也有自己的优点:可以直接访问系统接口,汇编程序翻译成的机器语言程序的效率高。主要用于嵌入式系统。
(3)第3代高级语言:面向用户的、基本上独立于计算机种类和结构的语言。最大的优点是:形式上接近于算术语言和自然语言,概念上接近于人们通常使用的概念,相比于前两代语言,高级语言易学易用,通用性强,应用广泛。
(4)第4代非过程化语言:编码时只需说明”做什么”,就可以直接给计算机下达命令,不需描述算法细节。
从应用角度来看,高级语言可以分为基础语言、结构化语言和专用语言。从描述客观系统来看,程序设计语言可以分为面向过程语言和面向对象语言。
SQL语句执行过程:
(1)客户端发送一条查询给服务器。
(2)服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果。
(3)服务器端进行SQL解析、预处理,再由优化器生成对应的执行计划。
(4)MySQL根据优化器生成的执行计划,再调用存储引擎的API来执行查询。
(5)将结果返回给客户端。
select语句执行顺序:
- 在WHERE子句中使用列别名,只能直接使用列名或者常量,原因是当Mysql评估求值where子句时,select子句中列值可能尚未确定,也就是Where子句先于Select子句执行。
- 在不同的DBMS中,关于列的别名的应用情况有所不同,在MySQL中,在where子句中,不能直接使用列别名,而语法上GROUP BY、HAVING、ORDER BY中可以使用。在Oracle中,where、group by、having子句中,只能直接使用列名或者常量,不能使用列别名,而Order by可以直接使用列别名,或列序号。
- Oracle是强大的DBMS,依据select语句执行顺序,Where、group by、having子句都在select子句之前执行。
- MySQL有不严谨之处,对SQL执行前不做足够的预检,SQL执行过程及解析步骤中,对发现的问题并不会中断执行,而是尽量地猜测其输出数据。
第十一讲——内连接/联接查询
连接查询也叫联接查询,是关系数据库中最主要的查询,主要包括内连接、外连接和交叉连接等,通过连接可以实现多表查询。无论什么数据库,都要基本遵循SQL ANSI/ISO标准,常用的有SQL86,SQL92。
内连接是一种最常用的连接类型,内连接查询实际上是一种任意条件的查询,使用内连接时,如果两个表的相关字段,满足连接条件,就从这两个表中提取数据,并组合成新的记录。也就是在内连接查询中,只有满足条件的元组,才能出现在结果关系中,不匹配的行不显示。
表分为主表和外键表,主表为提供数据的表,外键表为调用数据的表,通过建立外键约束,也就是在外键表中,插入主表的主键作为外键,建立了表与表之间的关联。
内连接的语法形式SQL86:
Select 字段列表
From 表1,表2…… Where 连接条件 [and 筛选条件] ……
语法说明:
- Where子句后面首先是多表之间的连接条件,需要用AND运算符将筛选条件与之联合
- 在多表连接中,From子句后面有多个数据源,而非仅一个数据源,数据源名称之间用英文逗号分隔
- Where子句之后的筛选条件语法与单表查询类似
内连接的语法形式SQL92:
Select 字段列表
From 表1 [别名] [inner] join 表2 [别名]
ON 连接条件
内连接的语法形式SQL92
[Where筛选条件] ……
语法说明:
- From子句后面有多个数据源,,与SQL86不同,SQL92中的数据源用在连接关键词[inner] join相连,[inner]可以省略,仅join就代表内连接。
- Join子句之后必须有ON子句,用来设置多表之间的内连接条件
- Where子句仅用于控制行筛选条件,用法与单表查询类似。
应用提醒:
- 相比SQL86,SQL92在当前应用更广泛
- 多表查询语句设计思路与单表查询相似,建议首先搭建查询语句的主要命令关键词,也就是select、where、from,再按照查询语句的指向顺序,逐步完善所需的各子句,也就是先from,然后where,最后select查询
- ON t1.
TeaNo
=t2.TeaNo
就是teacher表和class表连接的条件 - 取别名的目的是为了引用起来,别名仅在SELECT语句内部有效
- 通过“表名.列名”的形式来引用列,否则可能出现二义性
- 非多表共有的同名列在引用时,可以不需要“表名.列名”形式,单用列名也可以
应用提醒:
- 通过对题目的分析,这个查询需要三表连接实现
- 在SQL92标准中,通过两对join……on可实现三表连接
- 在SQL86标准中,三表连接是直接将待连接的三表用英文逗号分隔后,放在From子句后面,再在Where子句设置内连接条件与查询条件
应用提醒:
多表成功连接后,可以当作一个新的单表,在这个表上进行分组统计,就像单表统计查询一样。
应用提醒:
- 这个查询语句执行结果集返回空集,在确保查询语句没问题的情况下,说明系统中不存在用户需求的数据
- FROM score t1 JOIN score t2这个连接很特殊,左表和右表均为score成绩表,这是一种特殊的内连接,也称为自连接
- ON t1.
TeaNo
=t2.TeaNo
是自连接的条件 - 自连接中所有列都是两表共有同名列,所以对列的引用必须使用“别名.列名”的形式,否则将出现二义性
连接查询是任何数据库实现多表查询的重要方法。连接查询对多个表进行JSON运算,简单地说,就是先确定一个主表作为结果集,然后,把其他表的行有选择性地“连接”,在主表结果集上,而这个选择放手的不同就形成了。
第十二讲——不一样的流程控制函数
(1)IF(expr1,expr2,expr3)函数
功能:如果expr1是 TRUE (也就是expr1值非0且非空NULL) ,则 IF ( ) 函数的返回值为expr2;否则返回值则为expr3。
IF()函数的返回值为数字值或字符串值,具体情况视其所在的语境而定,IF()函数与其他计算机程序设计中的IF语句功能相似。
应用提醒:
- IF(score<60,‘不及格’,score)用来对数据源score成绩表中的score分数列下的值逐一进行判断
- ORDER BY 4 DESC将结果集按照第4列降序输出
(2)IFNULL(expr1,expr2)函数
功能:假如expr1不为 NULL,则 IFNULL( )的返回值为expr1;否则其返回值为expr2。IFNULL( )的返回值是数字或是字符串,具体情况取决于其所使用的语境。
应用提醒:
IFNULL(score,‘无成绩’)这个函数是专门用来对NULL值进行判断的,函数的返回值要么是第1个参数,要么是第2个参数。在这个案例中,非空时返回分数的原始值,为空时返回字符串’无成绩’
(3)NULLIF(expr1,expr2)函数
功能:用于检验提供的2个参数是否相等,如果相等,则返回NULL,如果不相等就返回第一个参数。
(4)CASE WHEN THEN 函数
应用提醒:
- CASE…WHEN…THEN…END是一个多重选择函数,也叫情况语句,就是可以根据不同情况进行不同处理的意思。
- CASE……END是这个语句的一头一尾,在应用时必须要用END来结束这个语句,否则语法出错。
- CASE语句两种方案的不同在于判断方式的不同,方案一是根据不同值来选择处理方式,方案二是根据条件判断来选择处理方式。
第十三讲——外连接查询
(1)外连接语法
外连接分为三种:
左外连接 LEFT [OUTER] JOIN
右外连接 RIGHT [OUTER] JOIN
全外连接 FULL [OUTER] JOIN
MySQL无全外连接,但可通过其他方式,达到全外连接的效果。内连接的连接关键词是JOIN,作为连接的一种,外连接的连接词,也少不了JOIN,为了和内连接进行区分,外连接加上了左、右和全对应的英文单词,组成了外连接的关键词,也就是LEFT、RIGHT和FULL。
整体语法说明(语法与内连接接近):
Select 字段列表
From 表1 [别名] left/right [outer] join 表2 [别名]
ON 连接条件
[Where筛选条件]
应用提醒:
- 在左外连接/右外连接时,会以一个表(左表/右表)为基表,全外连接时左表和右表所有的记录不做限制,都显示,两表连接条件不匹配的记录用**空值(NULL)**填充,可见左外连接、右外连接的结果集是包含了内连接的。
- MySQL无全外连接,但可通过联合多个查询达到全外连接的效果。
应用提醒:
- WHERE t2.
TeaNo
IS NOT NULL,这个条件代表右表(class表)中存在满足条件可连接的记录WHERE t2.TeaNo
IS NULL,代表右表(class表)中无法满足条件连接的记录 - IFNULL(‘非班主任’,t2.
ClassName
),是应用IFNULL()函数对查询结果集的NULL值进行处理
应用提醒:
- UNION ALL是将上下两个查询语句的结果集合并,对于重复的数据不作消除重复的操作。UNION也是将上下两个查询语句的结果集合并,但会将其中的重复数据消除。
- 被合并的所有查询结果集的列数和列顺序必须相同;对应列的数据类型必须兼容。
(2)交叉连接:
交叉连接是没有任何限制条件的连接,产生的结果集与线性代数的笛卡尔积一样,没有实际应用价值。
交叉连接的实现:
从第一张表依次取出每一条记录,与另一张表的全部记录逐个,无条件地匹配连接。交叉连接后,结果集的记录数、行数和字段数、列数如下:
记录数(行数) = 第一张表记录数 * 第二张表记录数
字段数(列数) = 第一张表字段数 + 第二张表字段数
SELECT 字段列表
FROM 表1 [别名] CROSS JOIN 表2 [别名]
(后面没有ON子句,不设连接条件)
应用提醒:
- stuinfo表有120行、14列;class表有4行、8列。
- 结果中包含了所有满足内连接条件、外连接条件等记录。
第14讲——特有的系统函数
(1)VERSION()
功能:获取MySQL版本号
(2)CONNECTION_ID()
功能:获取服务器的连接数
(3)DATABASE()和SCHEMA()
功能 :获取当前数据库名
(4)USER()、SYSTEM_USER()、SESSION_USER()、CURRENT_USER()和CURRENT_USER
功能 :均为获取当前用户的名称
(5)FOUND_ROWS()
功能:获取前面查询语句返回结果集的总行数
- LIMIT 0,10用来限制了select语句查询结果返回的行数,这个查询语句仅在结果集中显示从第0行开始的共10行数据
- LIMIT 100代表显示的前100行数据
- 查询到的结果集总共有240行,虽然SELECT语句用LIMIT 0,10限制了显示结果的行数,但FOUND_ROWS()函数获取总行数与限制无关
- SELECT语句中经常用LIMIT限制返回行数,如果不想用LIMIT限制返回行数,那么在SELECT查询中包含SQL、CALC、FOUND、ROWS选项,然后执行FOUND_ROWS()函数就可以,前面的选项就是为了后面函数执行做的准备
COUT(*)用来统计查询语句返回的结果集行数,与FOUND_ROWS()在很多情况下结果是一样。在实际应用场景中,应该灵活应用。
(6)ROW_COUNT()
功能:返回被前面SQL语句更新的、插入的或删除的数据记录行数。对比FOUND_ROWS()函数和ROW_COUNT()函数,前者是获取查询语句影响的行数,而后者是获取更新语句影响的行数。
(7)CHARSET(str)
功能:返回字符串str的字符集,一般情况这个字符集就是系统默认的字符集。
(8)COLLATION(str)
功能:返回字符串str的字符排序方式
(9)LAST_INSERT_ID()
功能:获取最后生成的AUTO_INCREMENT值
(10)PASSWORD(str)
功能:用于对字符串str进行加密。一般情况下,PASSWORD(str)函数主要是用来给用户的密码加密的
(11)ENCODE(str,pswd_str)
功能:加密函数,使用字符串pswd_str来加密字符串str。加密的结果是一个二进制数,必须使用BLOB类型的字段来保存它。
在score数据表中,stuno学号列不是BLOB类型的字段,所以被ENCODE加密函数处理后,显示的全是乱码。
(12)DECODE(crypt_str,pswd_str)
功能 :解密函数,使用字符串pswd_str来为crypt_str解密。crypt_str是通过ENCODE函数加密后的二进制数据,字符串pswd_str应该与加密时的字符串pswd_str是相同的
在此用DECODE(crypt_str,pswd_str)为ENCODE(str,pswd_str)加密的数据进行了解密,所以您看到的依然是正常的学号。
第15讲——连接查询语句的执行顺序
执行顺序:
FROM>JOIN>ON>WHERE>GROUP BY>AVG/SUM/MAX等聚合函数>HAVING>SELECT>DISTINCT>ORDER BY
表连接的效率直接影响着多表查询语句的执行效率。
表连接的执行顺序及需要注意的问题:
(1)选择一个驱动表
驱动表是指多表关联查询时,第一个被处理的表,使用此表的记录去关联其他表。驱动表的确定很关键,他会直接影响多表连接的关联顺序,也决定了后续关联时的查询性能。
(2)驱动表的选择原则
①在对最终结果集没影响的前提下,优先选择结果集最小的表作为驱动表。
②MySQL在选择前会根据where里的每个表的筛选条件,相应的对每个可作为驱动表的表做结果记录预估,预估出每个表的返回记录行数,再根据select里查询的字段的字节大小总和进行乘积,即每行查询字节数 * 预估行数 = 预估结果。结果集是作为选择驱动表的一个主要因素,但不是唯一因素。
系统预估结果行的规则:
通过WHERE来预估结果行数,如果WHERE里没有相应表的筛选条件,无论ON里是否有相关条件,默认为全表。如果WHERE里有筛选条件,但是不能使用索引来筛选,那么默认为全表。如果WHERE里有筛选条件,而且可以使用索引,那么会根据索引来预估返回的记录行数。
Extra参数的描述和说明:
- Using where:不用读取表中所有信息,仅通过索引就可以获取所需数据。
- Using temporary:表示MySQL需要使用临时表来存储结果集。
- Using filesort:当查询中包含order by操作,而且无法利用索引完成的排序操作称为“文件排序”。
- Using join buffer:该值强调了在获取连接时没有使用索引,并且需要连接缓冲区来存储中间结果。
- Impossible where:这个值强调了where语句会导致没有符合条件的行,即通过收集统计信息不可能存在结果。
- Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行。
- No tables used:查询语句中使用from dual或不含任何from子句。
应用提醒:
FROM score t2 JOIN course t3 ON t3.couno=t2.couno JOIN stuinfo t1 ON t1.stuno=t2.stuno这个部分表的顺序变化,并不会影响查询语句的执行顺序和策略
表与表之间的关联:
MySQL表与表之间的关联查询使用Nested-Loop join算法,顾名思义就是嵌套循环连接,但是根据场景不同可能有不同的变种:比如Index Nested-Loop join,Simple Nested- Loop join,Block Nested-Loop join,Betched Key Access join等。
使用索引关联:
Index Nested-Loop join
Batched Key Access join
未使用索引关联:
Simple Nested-Loop join
Block Nested-Loop join
连接查询是解决多表查询的重要方法,不同的select语句在执行效率上会有差异,特别是对于海量数据的多表查询,通过EXPLAIN语句可以深入了解在系统内部对查询的执行分析,以帮助DBA和程序员来优化自己的查询操作。
第16讲——常用嵌套查询
(1)嵌套查询
嵌套查询是通过子查询实现的,这样的子查询最常见的嵌入位置是在外层SELECT查询的WHERE子句。
根据子查询结果集的规模,可将子查询分为:标量子查询、列子查询、行子查询、表子查询。
应用提醒:
- 面对多表查询,表之间的关系列起着重要的纽带作用。
- 通常子查询的位置在关系比较运算符的右侧。
- 嵌套查询语句,执行时从内层子查询语句开始,逐层向外。
- 子查询必须用英文圆括号包围起来,否则有语法错误。
应用提醒:
- 对于列子查询,不能用简单的比较运算符形成外层查询的where条件。
- 列子查询作为外层 SELECT语句的查询条件, 常用IN运算符关联
应用提醒:
- 子查询在需要的时候可以嵌套多层,多可以嵌套到32层,嵌套的层级太多,会导致性能下降。
- 多层嵌套的子查询,建议从最内层子查询开始测试,逐步向外层延伸直到最外层
应用提醒:
- 测试内层子查询,此处查询返回结果集为1行,也就是行子查询。
- 行子查询嵌套在外层Select语句的where子句,再者通过=等于号比较。
- 本案例两层查询的数据源都是stuinfo学生表,这在嵌套查询中是允许的。
应用提醒:
- 表子查询的结果集就是一个若干行若干列的逻辑表。
- 所有select语句中能使用数据源的地方都可以嵌入表子查询。表子查询可以看作虚拟表,在select语句中,所有能够使用数据源的地方,都可以嵌入表子查询,表子查询嵌入比较常见的位置,是from子句。
- 为了能在外层查询语句中引用到内层查询的统计列,必须给统计列设置别名。
- 面对多表查询任务都可以分别通过嵌套查询或连接查询实现,在实际应用中,应根据效率优先原则确定。
小结:
(1)根据子查询结果集的规模:标量子查询、列子查询、行子查询、表子查询
(2)根据子查询是否依赖外部查询,将子查询分为:非相关子查询、相关子查询
(3)子查询的主要嵌入位置:外部Select语句的 Select、From、Where或 Having等子句内
(4)从优化查询的角度应尽量使用连接(JOIN)来代替子查询
第17讲——嵌套查询语句执行顺序
根据子查询是否具有独立执行能力,分为非相关子查询和相关子查询。从执行顺序来说,这两种子查询也不一样。
非相关子查询独立于外部的子查询,子查询总共执行一次,执行完毕后将值传递给外部查询。
相关子查询执行顺序:
针对上面查询案例,用相关子查询实现,并分析在系统内部的执行过程。
应用提醒:
- EXISTS 和 NOT EXISTS,是存在谓词,单目运算符,用来构成条件表达式,返回逻辑值(true或false)。
- WHERE EXISTS (子查询),这是EXISTS和NOT EXISTS用于查询条件设置的常见形式,如果子查询结果集为空,即表示不存在结果集,返回false;如果子查询结果集非空,即表示存在结果集,返回true。
- WHERE EXISTS (SELECT* FROM class t1 WHERE t1.TeaNo=t2.TeaNo),子查询条件中需要引用外层查询中的表列,形成了相关子查询。
查询语句执行顺序分析如下:
①分析器先找到teacher表并装入内存, 一个指针(如p1)先指向teacher表中的第一条记录,然后进入WHERE进而再分析内层的select语句
②内层的select语句后,再把class表装入内存, 另一个指针(如p2)指向class表中的第一条记录,分析内层WHERE后面的条件表达式,指针p2在class表中自上而下依次进行条件判断,最后基于内层查询分析出一个虚表VT2, 也就变成SELECT……FROM……WHERE EXISTS VT2
③如果虚表VT2为空,EXISTS 虚表VT2也就为false,不返回到外层SELECT,而p1指向下一条记录。如果虚表VT2非空,也就是有记录,那么EXISTS 虚表VT2为true,则返回到外层SELECT,并把p1指向的那条记录添加进外层select语句的虚表VT1当中
④ 这里嵌套的子查询语句执行完成,但外层主查询语句只执行了一次,也就是说p1仅指向了teacher的第一条记录,p1还要指向teacher表的下一条记录并分析,这样又进入了嵌套中的子查询语句,继续执行第②、③步
⑤当p1也指到了teacher表的结尾,整个查询语句结束,返回虚表VT1,并通过外层主查询select子句取出指定的各列
第18讲——视图及其应用
(1)视图为何物
视图:是一种基本的数据库对象,是将定义好的查询作为视图对象存储在数据库中。视图创建好之后,可以和表一样进行查询或更新操作,因此,视图也常称为虚表,几乎数据表可以执行的操作都可以在视图上进行。
(2)创建视图的命令:
Create or Replace view 视图名[别名1,别名2……]
As 查询语句
别名:可以给视图中的数据列取合适的别名。
(3)视图应用
应用提醒:
- CREATE VIEW 或CREATE OR REPLACE VIEW 都可创建一个新视图
- 视图命名建议按照view_名称格式
- AS用来引出一条查询语句
- 视图一旦定义成功,就会在相应的数据库中出现一个新的视图对象
应用提醒:
- 基于视图用最简单的select语句完成了查询任务
- 要定义合适有效的视图,根本还在于视图定义语句中的查询语句。
- 视图的意义首先是为用户集中提取了数据,其次隐蔽数据库的复杂性,使操作简便化
- 增加数据的安全性
- 提高表的逻辑独立性
- 视图中数据的源头仍然在基表中
视图的核心是AS后面的SELECT语句
定义视图时,可以在视图名后面为视图中的各列指定名称,之后也通过指定的名称进行引用
步骤:
1 首先查询出score表中成绩为59的情况
2 查询view_stuscore视图中成绩为59的情况
3 通过view_stuscore视图来修改分数59为60
4 检查view_stuscore视图中以上五位同学的成绩情况
5 检查score表中以上五位同学的成绩情况
UPDATE view_stuscore SET score=60 WHERE score=59
应用提醒:
- 完成本次数据更新任务,仅第3步就可以完成,前两步是首先检查视图以及生成视图的基表SCORE中的数据情况,后面两个步骤则是让您对比更新后视图和视图表中的数据情况。
- 视图是一个虚表,并不存储数据,通过视图所做的所有操作都需溯源到相应的基表,通过视图,看到的数据都存储在它的基表中,而基于视图更新数据时,也就是映射到基表来进行更新。
- 通过视图来插入、更新和删除数据时,都需要溯源到原表/基表来进行操作。
通过视图来插入、更新、删除数据时,都需要溯源到原表也就是基表来进行操作。我们说视图是虚表,基于视图可以做更新操作,但不是所有视图都能实现数据更新。视图有利于简化查询,但没有使用价值的视图应该及时删除。
小结:
视图是一种基本的数据库对象,是基于数据表或其它视图动态查询而产生的,因此,视图也常常被称为**“虚表”**。几乎数据表可以执行的操作都可以针对视图进行,但对视图进行的所有操作,归根到底都需要溯源到生成视图的基表。
视图的优势:
- 重用SQL语句
- 为用户集中提取数据
- 隐蔽数据库的复杂性,使操作简便化
- 增加数据的安全性
- 提高表的逻辑独立性等
每次使用视图时都必须处理查询执行时所需的任一个检查,如果用多个连接和过滤创建了复杂的视图,或者是嵌套了视图,可能会发现性能下降厉害,在部署使用了大量视图的应用前,应该进行性能测试。
视图的规则和限制:
- 视图必须唯一命名
- 视图数目没有限制,视图可以和表一起使用
- 创建视图,必须具有足够的访问权限
- 视图可以嵌套
- ORDER BY可以用在视图中,但如果从该视图检索数据,且SELECT 中也含有ORDER BY,那么该视图中的ORDER BY将被覆盖
- 视图不能索引,也不能有关联的触发器或默认值
第十九讲——数据插入
INSERT [INTO] <表名>[(列名1,列名2......)]
VALUES (列值1,列值2......)
INSERT [INTO]代表的是将VALUES关键词后面的一串值插入到指定的数据表中去。
也可以用下面这种形式:
INSERT [INTO] <表名>
SET 列名1=表达式1,列名2=表达式2......
这里用SET语句来指定各列对应的插入值
INSERT [INTO] <表名>[(列名1,列名2......)]
SELECT 子句
在插入语句中嵌入子查询,可以成批的插入数据,在这个插入语句中,用select语句代替了values的部分,而select子句如果返回的是多记录的结果集,就是向数据表中插入了多条记录。
插入作为一种SQL的操作,除了需要正确的语法外,还要求插入的数据必须与数据表中的约束不冲突,否则正确的语法也无法实现正常的插入操作。
应用提醒:
- 值列表与字段列表在数量和类型上必须完全匹配
- NULL值用作占位符,不能用单引号引起来
- 本例中两个NULL值,一个用于控制系统自动填充的值,一个就是NULL值本身
应用提醒:
- 这是一条不完整的记录插入操作,在INSERT INTO 中,Admin部分制定了两个待插入的列名列表,而在values子句里面对应地也是提供了2个值,所以插入操作成功。
- 本案例中并不只添加了用户名和密码2个值,而是多了一个管理员序号
应用提醒:
- VALUES这里用DEFAULT来向“管理员序号”列自动填充,效果与NULL一样
- 没有语法问题,但执行却报错,错误提示为‘Mary’值违反了‘NameQui’唯一约束,AdminName列下值不能出现重复
- 其实所有的数据更新操作都与约束相关,必须确保更新操作不与约束冲突,否则只能失败
应用提醒:
- 本案例插入语句没有语法问题。
- 插入失败的原因是,主键值不存在的情况下,无法从外键表中先行插入外键值,待插入的‘18085228’学号列值违反了stuinfo学生信息表与score成绩表之间的外键约束,其中学生表的学号列是主键,成绩表的学号列是外键,在主键值不存在的情况下,是无法先在外键表中让该值存在下来的。
- 必须先在主键表插入主键后,再从外键表插入外键,在stuinfo学生信息表将学号‘18085228’学生的信息插入成功后,再执行score成绩表的插入操作。
应用提醒:
- 在insert语句中嵌入子查询,可实现数据批量插入
- 本案例中,第1列是字段变量,第2列是字符常量
- 无论是单条记录还是批量记录插入,都要保证插入数据结构匹配,与约束不冲突等
小结:
INSERT插入作为一种SQL操作,除了需要正确的命令语法外,还要求插入的数据必须与数据表上的约束不冲突,否则正确的语法也无法实现正常的插入操作。
INSERT命令有以下几种语法形式:
- INSERT…VALUES语句可以向表中插入一行数据,也可以插入多行数据。使用单行insert语句插入多行数据时,用英文括弧括起来并用逗号隔开。
- INSERT…SET语句可以指定插入行中每列的值,也可以指定部分列的值。
- INSERT…SELECT语句向表中插入子查询检索到的批量数据。
第20讲——数据删除
在 MySQL中,可以使用DELETE语句来删除表的一行或者多行数据甚至所有的数据。并非数据表中的一个单独数据,而是一条完整的数据。
语法:
DELECT FROM <表名>
WHERE [筛选条件]
[ORDER BY 子句]
[LIMIT 子句]
语法说明:
- WHERE子句为可选项,表示为删除操作限定删除条件。若省略该子句,则代表删除该表中的所有行。
- ORDER BY子句为可选项。表示删除时,表中各行将按照子句中指定的顺序进行删除。
- LIMIT子句为可选项。用于告知服务器在控制命令被返回到客户端前被删除行的最大值。
如果要限制需要删除的行数,则配合ORDER BY使用LIMIT子句。
DELETE语句删除的是数据表中的数据行,可能是1行、多行甚至所有行,这与where条件限制有关
应用提醒:
- 命令没有语法问题,但却没有正常运行
- course课程表是父表,score成绩表是子表,不能删除成绩该一条父记录
- **“一删全删”**的效果虽然很智慧,但这也隐藏着较大的数据丢失风险
应用提醒:
- 删除主表数据的时候,同步删除掉子表的匹配记录
- 主外表之间设置了‘级联’修改即cascade方式,实现了‘一改全改’
- DBA在对数据库非常熟悉,有把握掌控数据风险的情况下,可以使用级联删除,否则较易造成数据丢失风险
如何在未设置级联更新的情况下达到一改全改的高效:
UPDATE 表1[INNER JOIN | LEFT/RIGHT JOIN]
表2 ON 连接条件
SET 列名1=表达式1,列名2=表达式2,......
WHERE 筛选条件
这里只能使用表名,不能使用别名
本讲小结:
- 为了数据安全,执行update命令需要相应权限的
- 执行update命令,可能产生数据一致性问题
- “级联更新”为保证数据一致性带来方便,但也存在“一改全改”的数据风险
第21讲——数据修改
UPDATE <表名>
SET 列名1=表达式1,列名2=表达式2,......
[WHERE 筛选条件]
语法说明:
- SET子句指定要修改的列和新值。要更新多个列,则用英文逗号分隔列表。
- WHERE子句是可选的,用于条件限定要更新的行,如果省略WHERE子句,则UPDATE语句将更新表中所有行的指定列。
应用提醒:
UPDATE数据修改命令语法简单,与delete操作是一样,都可能因为约束条件冲突导致操作失败。进行数据更新操作前,要充分的清楚数据库内数据的关系。
应用提醒:
- UPDATE修改命令语法正确,但修改失败的情况并不少见
- 如果没有设置**“级联”**更新,就不能删除或修改一条父记录
- “级联”更新实现了“一改全改”,但隐藏着较大的数据修改风险
一改全改:就是指从COURSE课程表,这个主表,修改大学英语的课程代码,则与之关联的SCORE成绩表,这个子表中的相关的成绩记录,会自动的修改其课程代码。一改全改的效果和已删全删的效果一样明显,但也同样隐藏着较大的数据风险。
UPDATE JOIN语法:
UPDATE 表1 [INNER JOIN | LEFT/RIGHT
JOIN] 表2 ON 连接条件
SET 列名1=表达式1,列名2=表达式2,…… WHERE 筛选条件
应用提醒:
- 在UPDATE子句之后,主表(表1)和连接表(表2),不能使用别名
- JOIN子句必须出现在UPDATE子句之后。
- 要为待更新的表1和/或表2表中的列分配新值。
- WHERE语句中的条件用于指定要更新的行。
第22讲——“增删改”有风险
不同用户对不同数据拥有不同的操作权限,每种数据库都有很完善的安全管理体系。
权限管理:
MySQL数据库实际上是通过将用户写入mysql库中对应的权限表来控制访问权限的。权限表分别为:user,db,table_priv,columns_priv。
(1)user:记录允许连接到服务器的用户的信息,里面的权限是全局性的
(2)db:记录每个用户对各个数据库级别的操作权限
(3)table_priv:记录每个用户对数据表级别的操作权限
(4)columns_priv:记录每个用户对数据列级别的操作权限
mysql通过赋予或撤销某个用户对某个数据库的或者某个数据表的某项权力,比如:读、写、更改、删除等等来保证数据安全。
应用提醒:
- user表是MySQL的权限表,用来记录相应的数据库服务器上每一个用户拥有的权限信息,比如select_priv、insert_priv等字段就是表明用户是否具有查询、插入等操作权限。这里反映用户u1是没有这些权限的。
- user表中host列的值的意义是%百分号表示匹配所有的主机。LOCALHOST表示不会被解析成IP地址,而是直接通过UNIXSOCKET来进行连接。127.0.0.1表示会通过TCP/IP协议连接,并且只能够在本机访问。
- user表中user列、password列存放用户名和密码,密码是加密存储的。
CRANT ALL PRIVILEGES ON *.*
TO 'USERNAME'@'LOCALHOST'
IDEHTIFIED BY 'PASSWORD'
CRANT命令用来给用户授权,ALL PRIVILEGES代表所有权限,ON *.*表示所有数据库。用户授予的权限是针对“school”数据库所有表的,不涉及其他数据库。
应用提醒:
- 无论是查询还是插入,在“school”数据库上都可以实现
- ALL PRIVILEGES代表全部权限
- 如果权限授予不合理,可以通过EVOKE ALL PRIVILEGES ON * . * FROM’username’@'localhost’来收回对所有数据库的所有权限
- CREATE创建对象,DROP删除对象,ALTER修改对象等等
应用提醒:
- 为不同的用户合理地分配相应权限,能有效控制不同用户对不同数据的操纵权限,是保护数据的一种有效手段。
- 仅授予该用户select操作权限。
应用提醒:
- 可以多次执行GRANT授权命令,为用户分配不同的权限
- 用户必须在权限控制范围内对数据库进行访问,否则超出权限的话,命令执行必须是失败告终
- 大型数据库权限管理更加复杂
第23讲——IN型参数存储过程编程
(1)存储过程:
存储过程是数据库的一个重要功能,是一组为了完成特定功能的SQL语句集合。使用存储过程的目的,是将常用或复杂的过程预先用SQL语句写好,并用一个指定的名称存储起来,这个过程经过编译和优化后,就在数据库中存储着,因此称为存储过程。当以后需要数据库提供与已定义好的存储过程相同功能的服务时,只需要用CALL命令来调用相应的存储过程即可。
存储过程的优点:
- 封装性:存储过程被创建后,可以在程序中多次被调用,而不必重新编写存储过程的SQL语句,数据库专业人员可以随时对存储过程进行修改,而不会影响到调用它的应用程序源代码,提高了应用程序的稳定性。
- 增强了SQL语句的功能和灵活性:存储过程可以用流程控制语句编写,有很强的灵活性,用于完成复杂的判断和比较复杂的运算。
- 减少网络流量:由于存储过程是在服务器端运行,而且执行速度快,因此当客户端上调用存储过程时,网络中传送的只是调用语句,而非整个存储过程的程序代码,从而可以降低网络负载。
- 高性能:存储过程执行一次后,产生的二进制代码就驻留在缓冲区,在以后的调用中,只需要从缓冲区中执行二进制目标代码即可,从而提高了系统的效率和性能。
- 提高数据库的安全性和数据完整性:使用存储过程可以完成数据库的几乎所有操作,并且可以通过编程的方式,控制数据库信息访问的权限。
过程控制语句:
① DECLARE语句:局部变量声明,可一次声明多个同类型局部变量
DECLARE是命令动词,说明在此进行的是变量声明,这里说明此处可以声明多个变量,当然变量名必须符合mysql标识符命名规则。数据类型名用来说明变量的数据类型,比如常用的INT整型、CHAR字符型等等。默认值是用来为各变量设置同一个默认值,这是一个可选项。
例子中N=1
② SET语句:赋值语句,可一次为多个变量赋值
SET与增删改查等SQL命令一样,命令动词,标识符等不区分大小写。后面的部分就是给变量赋值,也可以给多个变量赋值,各赋值表达式之间需要用逗号隔开。
③ SELECT … INTO语句:把查询选定的数据表列值存储到局部变量
只有查询结果为单一行时可执行此功能,与一般的select查询语句是一样的,但与之不同的是,这里的查询结果不是通过结果集反馈,而是通过INTO子句,把结果存到指定变量中去了。
分支结构控制语句:
情况分支:
过程控制语句:
无限循环在程序中称为死循环。条件藏在语句群中了。
BEGIN END复合语句,封装之后,这个语句群内所有的语句,要么都执行,要么都不执行。
存储过程的三种模式:IN默认的模式、OUT输出模式、INOUT输入输出模式。
第23讲——OUT型参数存储过程编程
存储过程的三种模式:IN默认的模式、OUT输出模式、INOUT输入输出模式。
应用提醒:
- 此处设计一个out型参数s,存储过程在启动时不像IN型参数,是无法访问OUT参数的初始值的
- SET s = 0; 是MySQL提供的变量赋值语句
- 在此通过select ……into来给OUT参数赋值,并通过OUT参数将新值传递回调用程序,select ……into也可以实现给变量赋值的功能
应用提醒:
- 调用存储过程时,提供的参数个数、类型、模式都要与当初定义一致。
- MySQL变量可用户变量和系统变量,该案例中第3个为OUT模式整型参数,调用时则需要对应提供一个变量来接收OUT参数传递出来的值。根据实际应用又会被细化为四种变量:局部变量、用户变量、会话变量和全局变量,在存储过程体内,用DECLARE声明的是局部变量,比如SNO CNO,它们的作用域仅仅在过程体BEGIN…END这个块内。调用语句中的@s则是用户变量,MySQL中用户变量不用提前声明,需要时直接以@变量名使用就可以了,它的作用域为当前连接,当前连接断开后用户变量就会消失。
- 会话变量和全局变量均为系统变量,MySQL的服务器为每个连接的客户端维护一系列的会话变量,他们的作用域仅限于当前连接,即每个连接中的会话变量时独立的,可以使用SHOW SESSION这样的语句来查看当前连接的会话变量。MySQL的全局变量能影响服务器的整体操作,当服务器启动时,所有的全局变量初始化为默认值,其作用域为MySQL服务器的整个生命周期。SHOW GLOBAL语句可以查看当前MySQL服务器的全局变量。
- MySQL变量的4种变量作用域关系为:局部变量<用户变量<会话变量<全局变量。
应用提醒:
- 3个参数,前2个IN型,第3个为OUT型参数。调用存储过程的语句,必须你找定义给予相应的参数,在这里前两个是字符串常量,第三个则是用户变量。
- IF嵌套实现了三重分支设计。过程体中IF…THEN…ELSEIF…实现了三重分支设计,即优秀、合格、不合格三种情况的判断和处理。
- 如果只判断合格和不合格两个情况,则仅需IF…THEN…ELSE…END IF。
- IF多层嵌套可实现多重分支。
应用提醒:
- 通过case语句实现多重分支判断,可以有效避免IF语句的多级嵌套。case作为一个专门的多重分支控制语句,用法得当可以有效的避免IF语句的多级嵌套。
- MySQL的控制语句都有开始与结束。也就像IF…END IF、CASE…END CASE、LOOP…END LOOP等等。编程时需要注意这些语句的对应关系。
第25讲——INOUT型参数存储过程编程
应用提醒:
- inout参数具有out参数的特性。都可以从过程内部传值给调用者。比如调用存储过程时,通过@XX,接收到了来自存储过程处理的结果。
- inout参数也具有in型参数的特性。
应用提醒:
- DECLARE语句声明游标。语法是DECLARE游标名CURSOR FOR SELECT语句。
- OPEN语句打开游标。OPEN语句初始化游标的结果集,因此必须从结果集中,提取行之前调用OPEN语句。语法是OPEN游标名。
- FETCH语句来检索光标指向的下一行,并将游标移动到结果集中的下一行。
- CLOSE语句来停用游标并释放与之关联的内存。语法是CLOSE游标名。
- 声明一个NOTFOUND处理程序来处理当游标找不到任何行时,也就是溢出时的情况。因为每次调用FETCH语句时,游标会尝试读取结果集中的下一行,一旦游标发生溢出,就会引发MySQL预定义的NOT FOUND这个错误;而过程体内声明游标后,即指定了引发NOT FOUND错误时定义的CONTINUE事件,并修改FLAG的值为1。
LOOP循环(IF FLAG=0跳出循环):
WHERE循环(单型循环,条件成立就继续循环,不成立就结束循环):
REPEAT UNTIL循环(直到型循环,每次执行循环体后判断UNTIL后面的条件,条件不成立就终止循环):
第26讲——通过触发器进行数据更新
一个数据库往往有很多个相互关联的数据表构成。
触发器(trigger):是用于监视某种情况,并触发某种操作的特殊的存储过程。是提供给程序员和DBA一种保证数据完整性的方法。更广泛的应用于加强数据的完整性约束和业务规则。它是一种与数据表事件相关的特殊的存储过程,触发器不是由程序调用,也不是手工启动,是由事件来触发。例如当对一个表进行增、删、改等更新操作时就会激活触发器。
触发器语法:
Create Trigger:创建触发器的命令事件
After/Before:触发时机
Insert/Update/Delete:触发事件/监视事件
On 表名:监视地点(某个数据表)
For Each Row:在创建触发器的语法中是固定的
sql语句:触发后的执行程序
应用提醒:
- 触发器与存储过程定义有些相似。都要设置对象名称,在BEGIN…END之间要定义执行体。
- 触发器与存储过程不同,不能设置参数。
- 对同一个表相同触发时间的相同触发事件,只能定义一个触发器。可以使用OLD和NEW来引用触发器中发生变化的数据内容 。比如NEW STUNO就提取到了新插入学生的学号。对于INSERT语句只有NEW是合法的。
- 所有插入操作,都不能与数据表本身的约束冲突,否则所有的操作都会失败。
应用提醒:
- 触发器中的删除操作也要注意,不能违反约束。因为学生信息表STUINFO主表与成绩表SCORE这个外表,本身就有主外键关系存在,基于主表来创建的话,主表的删除操作,本身就存在违反约束的问题,所以只能通过外表来创建基于删除操作的触发器。如果反过来,基于主表来创建触发器的话,就会违反外键约束而导致删除操作失败。
- 在DELETE语句中,可以通过OLD来取得被删除的数据行,不存在使用NEW的情况。
应用提醒:
- new:当触发插入和更新事件时可用。指向的是被插入的新纪录。
- old:当触发删除和更新事件时可用。指向的是被删除的老记录。
- 同时能使用new和old的,仅在update型触发器中。
- 无论什么触发器,更新操作首先必须不违背相关约束。
第27讲——PHP与MySQL
网站:
网站不只是用户见到的前端,更重要的是“幕后英雄”——数据库
PHP:
- PHP是一种易于学习和使用的服务器端脚本语言,只需要很少的编程知识你就能使用PHP建立一个真正交互的WEB站点。
- PHP 是能让你生成动态网页的工具之一,且PHP完全免费,只需要在官网下载即可使用。PHP可以编辑成和许多数据库相连接的函数。
- PHP 与MySQL是现在绝佳的组合。
MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了查询速度并提高了灵活性。
常用工具:
- 操作系统:操作系统: Windows系统、Linux系统(Ubuntu、CentOS、Redhat、FreeBSD……)
- 服务器发布工具:IIS、Apache、Nginx等
- 语言:PHP、JAVA、.Net、ASP、Python等
- 数据库:SQL、MySQL、MariaDB、Oracle等
常用组合:
Windows:IIS+.net+SQL
Linux: Apache+PHP+MySQL
常用快速面板工具:
- 部分国外云服务器提供Cpanel
- 自行安装可以安装Xampp PHPstudy(小皮面板)BT(宝塔面板)
- 这些面板工具大部分都集成了需要的控制管理、运行工具、安全工具等
apache是一个服务器,构建了PHP与数据库之间可以沟通的环境。apache相当于同声翻译员。
程序中PHP和MySQL的链接:
PHP 提供了 mysql_connect() 函数来连接数据库。该函数一共有5个参数,一般我们只用前面3个。
后台数据库如何沟通:
- server 规定要连接的服务器。可以包括端口号,例如 “hostname:port”,或者到本地套接字的路径,例如对于 localhost 的 “:/path/to/socket”。
如果 PHP 指令 mysql.default_host 未定义(默认情况),则默认值是‘localhost:3306’。 - user 用户名。默认值是服务器进程所有者的用户名。
- password 密码。默认值是空密码。
php mysql_close 用来断开与mysql数据库的联系。一般情况下,脚本运行完后,会自动断开与服务器之间的联系,所以这句也可以不写。
不过mysql_close是不会关闭的,因为MySQL_PCONNECT建立了持久连接,下面是写法:
<?php
header("content-type:text/html;charset=utf-8");
$servername =
"127.0.0.1";//服务器主机地址
$username =
"root";// 访问数据库的用户名
$password =
"root";//访问数据库的密码 //phpstudy的mysql有一个默认用户
名(root)和密码(root)
// 创建连接
$conn = mysql_connect($servername, $username,$password); // 检测连接
if (!$conn) {
die("Connection failed: "
. mysql_connect_error());//die()输出一条消息,然后断开 连接。
}
echo "连接成功";
mysql_close($conn);//关闭连接。
?>
如何通过语句使用PHP操作数据库:
(1)插入数据:
$sql="INSERT INTO admin(username,password,email)VALUES('admin','123456','123456789@qq.com')";
mysqli_query($conn,$sql);
(2)删除数据
$sql="DELETE FROM admin WHERE username='admin'";
mysqli_query($conn,$sql);
(3)更新数据
$sql="UPDATE admin SET email='309123793@qq.com'";
mysqli_query($conn,$sql);
(4)读取数据
$sql ="SELECT id, username, email FROM admin";
mysqli_query($conn,$sql);
—— THE END