本章需掌握MySQL常用的存储引擎,掌握增删改查数据库表常用的SQL语句,掌握模糊查询。
在前面章节学会了数据库的相关概念,需要明确对于MySQL数据库而言,数据最终以什么样的形式保存,以及数据保存在硬盘的什么位置,基于以上两个问题,本章将详细介绍MySQL数据哭的存储引擎。
本章将继续讲解SQL语句中的DML和DQL,并使用SQL语句完成对数据库表中数据的增加、删除、查询和修改,将继续使用Navicat进行管理MySQL.
MySQL属于数据库管理系统,其中包括数据库和用于数据库访问管理的接口系统。数据库赋值存储数据,接管口系统负责管理数据。为了满足不同用户对于数据库的容量、访问速度、数据完全性的要求,MySQL数据库采用多种存储引擎进行数据存储,下面将介绍MySQL数据库常用的存储引擎。
存储引擎指定了表的存储类型,即如何存储和索引数据、是否支持事务,同时存储引擎也决定了表在计算机中的存储方式。MySQL5.7支持的存储引擎有InnoDB、MyISM、MEMORY、MRG_MyISM、ARCHIVE、FEDERATED、CSV、BLACKHOLE,及PERFORMANCE_CHEMA共9种,可以使用SHOW ENGINES语句查看系统所支持的引擎类型,执行结果如下
默认情况下FEDERATED存储迎请是未开启状态。
不同的数据引擎有不同的特点,以适应不同的用户需求,本章重点介绍脸各种常用的存储引擎INNODB和MyISAM。我们在选择使用哪种存储引擎之前,首先需要对比他们所提供的功能,
功能 | InnoDB | MyISAM |
支持事物 | 支持 | 不支持 |
外键约束 | 支持 | 不支持 |
表空间大小 | 较大 | 较小 |
数据航锁定 | 支持 | 不支持 |
InnoDB和MyISAM各自的适用场景如下:
InnoDB存储引擎:该引擎在事物处理上具有优势,即支持具有提交、回滚和崩溃恢复能力的事务控制。因此InnoDB适用于需要进行频繁的更新、删除操作,同时还对事物的完整性要求比较高,需要实现高并发控制等的应用前景。
MyISAM存储引擎:该存储引擎不支持事物,也不支持外键约束,占用空间小,访问速度快。因此MyISAM适用于不需要事物处理,以访问为主的应用场景。
MySQL5.7版本默认的存储引擎是InnoDB,可以通过一下语句来查看当前默认的存储引擎:
SHOW VARIABLES LIKE 'default_storage_engine%';
其中,LIKE后要查询的关键字‘default_storage_engine%’,表示默认存储引擎,如需要修改默认存储引擎,可以通过配置向导,也可以通过修改配置文件my.ini来实现,只需要修改以下内容。
default-storage-engine=INNODB
例如,若需要将默认引擎改为MyISAM,只需修改为‘default-storage-engine=MyISAM’即可,从新启动后再次查看就会得到MyISAM的默认存储引擎。
数据表默认使用当前MySQL默认的存储引擎,有时为了达到数据表的特殊功能,也可重新设置表的存储类型。语法格式如下。
CREATE TABLE 表名(
...
)ENGINE=MyISAM;
【示例一】创建myisam表并设置引擎为MyISAM类型
CREATE TABLE myisam(
`id` INT(4)
)ENGINE=MyISAM;
上文介绍了MySQL的存储引擎如何设置,那么MySQL的数据文件是怎样的,他们又如何存放,在MySQL中,不同的存储引擎涉及的数据文件有所不同。
【示例二】
创建两个不同类型的数据表。
CREATE DATABASE enginedb;
USE enginedb;
#创建表类型为MyISAM的表
DROP TABLE IF EXISTS `myisam`;
CREATE TABLE `myisam`(
`sid` INT(4)
)ENGINE=MyISAM;
#创建表类型为InnoDB的表
CREATE TABLE `innodb`(
`sid` INT(4)
)ENGINE=InnoDB;
以上代码实现了在enginedb数据库中创建两个表,其中myisam表位MyISAM类型,innodb表位InnoDB类型。
(1)数据文件的存储位置。不同操作系统文件的默认位置不同,win10操作系统中,MySQL文件的默认存储路径为C:\ProgramData\MySQL\MySQL Server 5.7\Data,可以通过配置文件my.ini中的参数datadir获取和修改该路径例如
datadir=C:\ProgramData\MySQL\MySQL Server 5.7\Data
在该目录下,每个数据库相关文件均存放在以数据库命名的文件夹下,可以找到enginedb数据库文件夹,如下
(2)MyISAm类型的表文件。打开enginedb文件夹,找到MyISAM的表myisam相关的数据文件,找打类型为MyISAM表相关的数据文件,共有三个,扩展名分别为.frm、MYD、.MYI,如图所示:
.frm文件:表结构定义文件。主要存放表的元数据,包括表结构定义信息等,该文件与存储引擎无关,即任何存储类型的表都会有这个文件。
.MYD文件:数据文件。存放表中的数据。
.MYI文件:索引文件。其主要存放MyISAM类型的表的索引信息,每个MyISAM类型的表都会有一个.MYI文件,其存放的位置和.frm文件相同。
(3)InnoDB类型的表文件。InnoDB类型的表innodb又.frm和ibdata 1两个相关文件,其中.frm文件在enginedb数据库文件目录下。
.frm文件:表结构定义文件,其作用与MyISAM类型的.frm文件相同。
ibdata 1文件:数据文件。保存所有InnoDB类型的表的数据。这个文件保存位置与.frm文件不同,可以通过my.ini文件中的参数innodb_data_home_dir查询或修改。默认情况下,会在my.ini文件中的参数innodb_data_home_dir参数所设置的目录下创建ibdata1作为innodb数据表空间。这里的datadir参数新设目录为:C:\ProgramData\MySQL\MySQL Server 5.7\Data
我们已经了解了如何创建表、修改标的结构和添加约束,现在还要学习如何想表中添加数据,这里介绍如下两种方式。
(1)在Navicat中插入数据,这种港式比较简单,只需要右击表,在弹出的快捷菜单中选择打开表选项,就可以直接输入数据行。
(2)使用SQL向表中添加新数据,或者将现有表中的数据添加到新创建的表中。
语法格式如下
INSERT INTO 表名 [(字段名列表)] VALUES(值列表);
需要注意以下几点:
1 表的字段是可选地,如果省略,则依次插入所有字段
2多个列表和多个值之间使用逗号分隔
3值列表必须和字段名列表数量相同,且数据类型相符
4 如果插入的是表中部分列的数据,则字段名列表必须填写
【示例三】
向student表中插入一条记录:
INSERT INTO `student`
(`loginPwd`,`studentName`,`gradeId`,`phone`,`birthday`)
VALUES('123','HXP',1,'13998328813','1999-8-8');
插入数据需要注意这个表是否与其他表存在外键关系,如果该表存在外键,但是相关联的表中数据缺失,则插入数据就会失败,例如在之前的章节的讲解中,student表中的gradeId作为外键与grade表进行关联,因此,在上面的例子中,要插入的数据学生所属gradeId为1,如grade表中不存在年级为1的记录,则插入数据就会报错。因此外键可以保证数据完整性
MySQL中的INSERT语句支持一次性插入多条记录,插入时可指定多个值列表,每个值列表之间用逗号分隔。语法格式如下:
INSERT INTO 新表 (字段名列表) VALUES(值列表1),(值列表2);
【示例4】一次性向subject表中插入3条数据
INSERT INTO `subject`
(`subjectName`,`classHour`,`gradeId`)
VALUES('Logic Java',200,1),
('html',160,1),
('java oop',230,2);
在使用INSERT语句插入记录时,如果不包含字段名称,VALUES关键字后面的值列表中的个字段顺序必须与表定义中的各字段的顺序相同,如果表结构变了(如执行了添加字段操作),则值列表也要变化,否则会出现错误,如果制定了插入的字段名,就会避免这个问题,因此在插入数据时制定具体的字段名。
MySQL中的CREATE TABLE语句可以实现将查询结果插入新表中,语法如下:
CREATE TABLE 新表(SELECT 字段1,字段2,...FROM原表);
【示例5】将student表中的studentName字段、phone字段保存在新表phoneList中
关键代码:
CREATE TABLE `phoneList` (SELECT `studentName`,`phone`FROM student);
以上SQL语句在执行查询操作的同时创建新表phoneList,无须提前创建,Navicat工具中的执行结果如下,若存在phoneList表则会报错
上机练习1
为课程表、学生表、成绩表添加数据
(1)
课程编号 | 课程名称 | 课时数 | 年级编号 |
1 | logicjava | 220 | 1 |
2 | html | 160 | 1 |
3 | javaoop | 230 | 2 |
INSERT INTO `subject`(`subjectName`,`classHour`,`gradeId`)
VALUES('logicjava',220,1),('html',160,1),('javaoop',230,1);
(2)为学生表添加数据
学号 | 密码 | 学生姓名 | 性别 | 年级编号 | 手机号码 | 地址 | 出生日期 |
10000 | 123 | gj | m | 1 | 11222 | tj | 1998-08-08 |
10001 | 123 | gjx | m | 1 | 11222 | bj | 1998-08-08 |
INSERT INTO `student`(loginPwd,studentName,sex,gradeId,phone,address,birthday)
VALUES('123','gj','m',1,'112222','tj','1998-8-8'),
('123','gjx','m',1,'112222','bj','1988-8-8'),
('123','gj','m',1,'112222','sh','1998-8-8'),
('123','gj','m',1,'112222','cq','1998-8-8'),
('123','gj','m',1,'112222','wh','1998-8-8'),
('123','gj','m',1,'112222','hb','1998-8-8'),
('123','gj','m',1,'112222','wh','1998-8-8'),
('123','gj','m',1,'112222','hz','1998-8-8')
;
(3)为成绩表添加数据
学号 | 科目 | 时间 |
10000 | 1 | 2000-03-02 |
10001 | 2 | 2000-03-02 |
10002 | 3 | 2000-03-02 |
INSERT into results (studentNo,subjectNo,examData,studentResult)
VALUES(1,1,'2000-03-02',90),
(2,2,'2000-03-02',90),
(3,3,'2000-03-02',90);
数据更新是经常发生的事情,使用SQL可更新表中某行数据。语法格式如下
UPDATE 表名 SET 列名=更新值 [WHERE 更新条件];
其中:
(1)SET关键字后面可以紧随多个“列名=更新值”以修改多个数据列的值,不限一个,不同列之间使用逗号分隔;
(2)WHERE子句是可选地,用来选址更新的条件,若不限制,则整个表的数据将会被改变,需要注意的是update可能更新一行数据,也可能更新多行数据,可能不会更新任何数据
【示例6】在学生表中,要把所有学生的性别都改为‘F’女生
UPDATE student SET sex='f';
【示例7】将地址为tj的学生班级改为bjjjj
UPDATE student SET address='bjjjjj' WHERE address='tj';
【示例8】如果学生在考试时有一道题目的标准答案打错了,导致评分失误,事后需要在地狱或等于95分的成绩上加5分;
UPDATE RESULTS SET studentresult=studentresult+5 WHERE studentresult<=95;
删除数据行也是经常会用到的操作,使用SQL语句来删除数据的操作比较简单
DELETE [FROM] 表名 [WHERE <删除条件>];
删除学生表中删除姓名为gjx的数据
DELETE FROM student WHERE studentName='gjx';
还有一种情况,如果要删除的行的主键在被其他表引用,例如,学生表中的studentNo列被分数表中的studentId引用,那么删除被引用行的雨具如下
DELETE FROM student WHERE studentNo=1;
DELETE语句删除的是整条记录,不会只删除单列,所以在DELETE后不能出现列明
TRUNCATE TABLE语句可用来删除表中的所有航,功能上类似于没有WHERE子句的DELETE子句
【示例10】
使用TRUNCATE TABLE实现删除学生表中的所有记录行
TRUNCATE TABLE student;
上机练习2 修改学生表、课程表数据
(1)将学生表中学号为4的学生的地址修改为‘hn’,密码改为‘000’
(2)将课程表中课时数大于200且年级编号为1的可成的课时数减少10.
(3)将所有年级编号为1的学生姓名、性别、手机号码、出生日期信息保存到新表student_grade_1中
UPDATE student set address='hn',loginPwd='000' WHERE studentNo=4;
UPDATE subject set classHour=classHour-10 WHERE classHour>=200 AND gradeId=1;
CREATE TABLE student_grade_1(SELECT studentName,sex,phone,birthday from student WHERE gradeId=1);
上机练习3 删除学生数据
(1)由于入学年龄条件限制,学校要求不允许1997年1月一日后出生的学生入学,由于操作失误,现在需要删除。
(2)新学期开始,HXP同学转学,需要删除该同学的相关个人信息
DELETE FROM student WHERE birthday<'1997-01-01';
DELETE FROM results WHERE studentNo=5;
使用SELECT语句,最简单的查询语句格式如下:
SELECT <列名|表达式|函数|常亮>
FROM <表名>
[WHERE <条件表达式>]
[ORDER BY <排序的列名>[ASC或DESC]];
其中WHERE 子句是可选地,若不限制则返回整个表所有行的数据。
查询语句可以分为多个子句,例如上面的查询语法可以划分为SELECT ... FROM...WHERE...ORDER BY四个子句,对于复杂的SQL语句可以将每个子句单独写成一行,方便调试
(2)在查询语句中还可以使用其他的关键字来实现其他特殊的要求。如果要查询所有航和列可以使用*表示所有的列。
【示例11】查询学生表所有信息
SELECT * FROM student;
(2)查询部分行和列。查询部分列需要列举不同的列名,而查询行需要使用WHERE子句进行条件查询
【示例12】查询学生表中地址为‘hn’的学生信息
SELECT studentNo,studentName,address FROM student WHERE address='hb';
以上查询语句只查询地址为‘hb’的学生,并且只显示学号、姓名和地址列
【示例13】查询地址不是‘hb’的学生信息
SELECT studentNo,studentName,address FROM student WHERE address<>'hb';
以上查询语句查询的是地址为‘hb’以外的学生,且显示这些学生的字号、姓名和地址列
(3)在查询时使用列的别名。AS子句可以用来改变结果集中列的名称,也可以为组合或计算出的列指定名称,还可以让标题列的信息更加易懂。
【示例14】查询学生表中的地址不是‘hb’的学生信息,并将studentNo列的列名显示为‘学号’,将studentName列的列名显示为‘学生姓名’,将address列的列名显示为‘地址’
SELECT studentNo AS xh,studentName AS xsxm,address as dz
FROM student
WHERE address <> 'hb';
(4)查询空值,在SQL语句中采用‘IS NULL’或者‘IS NOT NULL’来判断值是否为空
【示例15】查询学生中没有填写E-mail的学生
SELECT studentName FROM student WHERE email IS NULL;
【示例16】查询学生信息的时候,学校名称统一的都是bjxxq
SELECT studentName AS xsxm,address as ad,'bjxxq' AS xxname FROM student;
查询输出结果多了一列‘xxname’,该列所有数据均是bjxxq
MySQL中的函数会讲一些常用的处理数据的操作封装起来,这样能大大简化程序员的工作,提高了开发效率。因此用户除了要会使用SQL语句之外,还需要掌握一些常用函数。以下分类列出了MySQL中的常用函数。
(1)聚合函数。MySQL中的聚合函数用来对已有数据进行汇总,如求和、平均值、最大值、最小值等。MySQL中的常用的聚合函数如表所示
函数名 | 作用 |
AVG() | 返回某字段的平均值 |
COUNT() | 返回某字段的行数 |
MAX() | 返回某字段的最大值 |
MIN() | 返回某字段的最小值 |
SUM() | 返回某字段的和 |
【示例17】计算小学生的总成绩
SELECT SUM(studentResult) FROM results;
【示例18】计算小学生的平均成绩可以使用AVG()函数
SELECT AVG(studentResult) FROM results;
(2)字符串函数。字符串函数用来对字符串进行各种处理MySQL中的字符串函数如表所示
函数名 | 作用 | 举例 |
INSERT(str,pos,len,newstr) | 将字符串str从pos位置开始,成都为len子串替换为新的子串newstr | 举例SELECT INSERT('这时MySQL数据库',3,10,'MySQL'); |
LOWER(str) | 将字符串str中的所有字符变为小写 | SELECT LOWER('mysql');返回MYSQL |
SUBSTRING(str,num,len) | 返回字符串str中的第num个位置开始长度为len的子字符串 | SELECT SUBSTRING('JavaMySQLOracle',5,5); 返回MySQL |
UPPER(str) | 将字符串 | SELECT UPPER('MySQL');返回MySQL |
LOCATE(substr,str) | 返回子串substr在字符串str中第一次出现的位置 | SELECT LOCATE('AND','MySQLAndOracle'); |
【示例19】规定学生的首字母必须大写,输出正确的学生姓名列表
SELECT UPPER(studentName) FROM student;
(3)时间日期函数。除了聚合函数和字符串处理函数以外,时间函数也是MySQL中的常用函数。
函数名 | 作用 | 举例(部分结果与当前日期有关) |
CURDATE() | 获取当前日期 | SELECT CURDATE(); 返回2029-08-8 |
CURTIME() | 获取当前时间 | SELECT CURTIME(); 返回14:20:20 |
NOW() | 获取当前日期和时间 | SELECT NOW(); |
WEEK(date) | 返回date为一年中的第几周 | SELECT WEEK(NOW()); 返回26: |
YEAR(date) | 返回日期date的年份 | SELECT YEAR(NOW()); |
HOUR(time) | 返回时间的小时数 | SELECT HOUR(NOW()); |
DATEDIFF(date1,date2) | 返回日期参数date1和date2之间相隔的天数 | SELECT DATEDIFF(NOW(),'2018-09-09') |
ADDDATE(date,n) | 计算日期参数date加上n天后的日期 | SELECT ADDDATE(NOW(),5); |
【示例21】
统计学生的出生年份
分析如下采用YEAR(date)函数关键代码
SELECT YEAR(birthday) FROM student;
(4)数学函数,在使用SQL语句进行数据操作时,有时也会需要进行数值运算,MySQL支持的常用的数学函数如表所示
CEIL() | 返回大于等于数值X的最小整数 | SELECT(2.3)返回3 |
FLOOR(x) | 返回小于或等于数值x的最大整数 | SELECT FLOOR(2.3); |
RAND() | 返回0-1的随机数 | SELECT RAND() |
【示例21】
对学生的分数取整并输出,采用ceil(x)函数
SELECT CEIL(studentResult) from results;
上机练习4查询学生相关基本信息
(1)查询所在年级ID为1的全部学生信息
(2)查询所在年级ID为2的全部学生的姓名和电话
(3)查询所有年级ID为1的全部女学生的信息。
(4)查询课时超过60的课程信息,将以上查询SQL保存为“查询学生相关基本信息.sql”文件
SELECT * FROM student WHERE gradeId=1;
SELECT studentName,phone FROM student WHERE gradeId=2;
SELECT * FROM student WHERE gradeId=1 AND sex='f';
SELECT * FROM subject WHERE classHour>=60;
上机练习5 查询学生相关复杂信息
(1)查询所在年级ID为1的课程名称
(2)查询所在年级ID为2的所有男学生的姓名和住址。
(3)查询没有电子邮件的学生姓名和年级信息。
(4)查询所在年级ID为1的学生中1990后出生的学生姓名。
(5)查询参加了日期为2000年3月2号的‘Logic Java’课程(也就是课程1)考试的学生信息。
(6)查询参加了‘HTML’课程(也就是课程2)的学生总成绩。
(7)查询参加了‘JavaOOP’课程(也就是课程3)考试的学生的平均成绩
SELECT subjectName FROM subject WHERE gradeId=1;
SELECT studentName,address FROM student WHERE gradeId=2;
SELECT studentName,gradeId FROM student WHERE email IS NULL;
SELECT studentName FROM student WHERE gradeId=1 AND birthday<='1990-01-01';
SELECT studentNo FROM results WHERE examData='2000-03-02' AND subjectNo=1;
SELECT SUM(studentResult) FROM results WHERE subjectNo=2;
SELECT AVG(studentResult) FROM results WHERE subjectNo=3;
上机练习6 使用函数查询学生信息
(1)查询年龄超过20周岁年级编号为1的学生信息(假设一年365天)。
(2)查询一月过生日的学生信息。
(3)查询今天过生日的学生姓名及所在年级。
(4)查询学号为2000的学生的email域名。例如假设他的email地址为'[email protected]',则查询出他的域名为yahhoo.com
(5)新生入学,为其分配一个Email的地址,规则如下S1+当前的日期+四位随机数[email protected]
SELECT * FROM student WHERE (DATEDIFF(NOW(),birthday)>=365*20) AND gradeId=1;
SELECT * FROM student WHERE SUBSTRING(birthday,6,2)='01';
SELECT studentName,gradeId FROM student WHERE birthday=NOW();
UPDATE student SET studentNo=2000,email='[email protected]' WHERE studentNo=5;
SELECT SUBSTRING(email,4,10) FROM student WHERE studentNo=2000;
INSERT INTO student (loginPwd,studentName,email) VALUES('122','NAME',CONCAT('S1',NOW(),RAND()*10000+1000,'@jbit.com'));
3 ORDER BY子句
如果需要将查询结果按照一定顺序排列,则需要使用ORDER BY 子句,并且排序可以是升序或者降序。如果不指定将默认按照升序排列。
【示例22】查询学生成绩示,需要把所有成绩都降低10%后加5分,在此基础上在查询及格程序并从低到高进行排列:
SELECT studentNo AS SN,(studentResult*0.95+5) AS grade FROM results
WHERE ((studentResult*0.95+5)>=60) ORDER BY studentResult;
【示例23】输出成绩信息,要求在学生成绩排序的基础上,在按照课程编号进行排序
SELECT studentNo as SN,subjectNo as SN,studentResult AS grade
FROM results
WHERE studentresult>60
ORDER BY studentResult ASC,subjectNo ASC;
上机练习7 使用排序查询学生相关信息
(1)查询年级编号为1的学生信息并按照出生日期升序排列。
(2)查询学号为1的学生参加过的所有考试信息,并按照时间先后顺序显示。
(3)按日期先后、成绩由高到低的次序查询编号为1的课程考试信息。
SELECT * FROM student WHERE gradeId=1 ORDER BY birthday ;
SELECT * FROM results WHERE studentNo=1 ORDER BY examData;
SELECT subjectNo FROM results WHERE subjectNo=1 ORDER BY examData desc,studentResult ASC;
SELECT *
FROM student
WHERE gradeId=1
ORDER BY studentNo;
SELECT *
FROM student
WHERE gradeId=1
ORDER BY studentNo;
4 LIMIT子句
以上操作实现了对数据表的基本查询操作,但是展示的是一个数据表中的全部数据,但在实际开发中,可能只要求显示指定位置制定行数的记录,使用LIMIT子句可实现限制查询出的位置和数目的目的。
SELECT <字段名表>
FROM <表名或试图>
[WHERE<查询条件>]
[GROUP BY <分组的字段名>]
[order BY <排序的别名> [asc或desc]]
[LIMIT[位置偏移量],行数];
上述语法中的LIMIT部分介绍如下
(1)位置偏移量。位置偏移量是指从结果集中第几条数据开始显示(第一条数据的位置偏移量是0,第二条记录的位置偏移量是),该参数可选,省略是将从第一条记录开始显示。
(2)行数。行数是指显示记录的条数。LIMIT子句可以实现数据的分页查询,即从一批结果数据中规定每页显示多少数据,也可以查询中间某业数据,LIMIT子句经常与ORDER BY 子句一起使用,即先对查询结果进行排序,然后根据LIMIT的参数显示部分数据。
【示例24】查询所有年级编号为1的学生信息,按学号升序排列前四条记录
SELECT * FROM student WHERE gradeId=1 ORDER BY studentNo LIMIT 4;
以上代码生录了位移偏移量,即从第一条记录开始显示
【示例25】查询所有年级编号为1的学生信息,其中每页显示四条数据,要求输出第二页的数据
经过分析应该从低5条数据开始显示4条信息,
SELECT * FROM student WHERE gradeId=1 ORDER BY studentNo LIMIT 4,4;
上机练习8 查询学生信息
(1)查询2019年2月17日考试成绩前5名的学生的学号和分数。
(2)查询ID为2的年级开设的课时最多的课程名称。
(3)查询年龄最小的学生的姓名及所在的年级。
(4)查询2019年2月17日参加考试的学生的最低分出现在哪门课程。
(5)查询学号为1000的学生参加过的所有考试中的最高分及时间、课程。
(6)将所有女给学生按年龄从大到小排序,从第二条记录开始显示留名女学生的姓名、年龄、出生日期、手机号码等信息。
(7)查询参加2019年2月17日考试的所有学生的最高成绩、最低成绩、平均成绩。
SELECT studentNo,studentResult FROM results WHERE examData='2019-02-17' ORDER BY studentResult LIMIT 5;
SELECT subjectName FROM subject WHERE gradeId=2 ORDER BY classHour LIMIT 1;
SELELCT studentName,gradeId FROM student ORDER BY BIRTHDAY DESC LIMIT1;
SELECT subjectNo FROM results WHERE examData='2019-02-17' ORDER BY studentResult DESC LIMIT 1;
SELECT examData,subjectNo FROM results WHERE studentNo=1000 ORDER BY studentResult limit 1;
SELECT studentName, (YEAR(NOW())-YEAR(birthday)) AS age ,birthday AS BD,phone WHERE sex='f' ORDER BY birthday DESC;
SELECT MAX(studentResult),MIN(studentResult),AVG(atudentResult) FROM results WHERE examData='2019-02-17';
任务目标:认识通配符,会使用LIKE、BETWEEN和IN关键字进行模糊查询,在前面的章节中,使用了SELECT语句来进行查询,WHERE子句中可以用=来获取数据的条件,如age=20.但是在实际应用中,有时查询者对查询条件也是模糊的。例如:我只想查询张姓学生的信息,查询分数在60-80分的考试或者查询上海、广州地区的学生,这种查询不是制定某个人的姓名、某个具体的分数或者某个固定的地区,这种查询都属于模糊查询。
模糊查询可以使用LIKE关键字、通配符来进行 IS NULL也是一种模糊查询,模糊查询还有基于某个范围内的查询和某些列举值内的查询
简单来讲,通配符是一类字符,它可以代替一个或多个真实地字符,查找信息时替代字符出现,SQL中的通配符必须与LIKE关键字一起使用,以完成特殊的约束和要求。
通配符 | 解释 | 举例 |
- | 一个字符 | ALIKE 'C_',则符合条件的如CS、Cd等 |
% | 任意长度的字符串 | BLIKE'CO%',则符合条件的如Const、COKE |
[] | 括号中所指定范围内的一个字符 | CLIKE'9W0[0-9]',则符合条件的C有9W01,9W02 |
[^] | 不再括号中所制定范围内的任意一个字符 | DLIKE '9W0[^1-2],则符合条件的又如9W07' |
通常,在查询语句中,使用LIKE子句进行模糊查询的关键语法如下所示
SELECT <列名>
FROM <表名>
WHERE <列名> LIKE 条件1 [AND [OR]] <列名>='值';
LIKE子句用来匹配字符串或字符串的一部分,由于该运算只用于字符串,因此仅与字符数据类型(char或varchar等)联合使用。
在进行数据更新、删除或者查询的时候,都可以使用WHERE....LIKE字符串进行匹配查找。
【示例26】查询学生表,输出所有张姓学生的信息
SELELCT * FROM student WHERE studentName LIKE '张%';
【示例27】查询学生表中地址包含'bj'字样的学生信息
SELECT * FROM student WHERE address LIKE '%bj%';
使用关键字BETWEEN可以查询那些介于两个已经知道值之间的一组未知值。要实现这种查询,就必须知道查询的初值和终值,并且初值需要小于或等于终值,初值和终值用AND关键字分开。
【示例28】查询成绩表中分数在60(含)分到80分的学生信息
SELECT *FROM results WHERE studentResult BETWEEN 60 AND 80;
【示例29】查询学生表中在1990-1-1到1993-12-31出生的学生信息
SELECT * FROM student WHERE birthday BETWEEN '1990-01-01' AND '1993-12-31';
【示例30】查询学生表中不在1990-1-1到1993-12-31出生的学生信息
SELECT * FROM student WHERE birthday NOT BETWEEN '1990-01-01' AND '1993-12-31';
如果查询的值是置顶的某些值之一,可以使用带列举值的IN关键字进行查询,将列举值放在圆括号里,用逗号分隔。
【示例31】
查询学生表中电话前三位是137、135、136的学生的信息66
SELECT * FROM student WHERE SUNSTRING(phone,1,3) IN ('137','135','136');
上机练习9使用模糊查询查询相关学生信息
(1)查询住址在'bj'的学生姓名、电话、住址。
(2)查询名称中含有'数据库'字样的科目名称、学时及所属年级,并按年级由低到高显示。
(3)查询电话中以‘1356’开头的学生的姓名、住址和电话。
(4)查询姓名为‘张*’的学生的学号、姓名和地址,其中*代表一个字。
(5)查询学号为10005的学生参加的科目编号为1,2,3的考试成绩信息。
(6)查询出生日期为‘1989-1-1’到‘1995-12-31’的学生信息
SELECT studentName,phone,address FROM student WHERE address LIKE '%bj%';
SELECT subjectName,classHour,gradeId FROM subject WHERE subjectName Like '%数据库%' ORDER BY gradeId DESC;
SELECT studentName,address,phone FROM student WHERE SUBSTRING(PHONE,1,4)='1356';
SELECT studentNo,studentName,address FROM student WHERE studentName LIKE '张-';
SELECT studentResult FROM results WHERE studentNo=10005 AND dubjectNo IN (1,2,3);
SELELCT * FROM student WHERE birthday BETWEEN '1989-1-1' AND '1995-12-31';
本章小结
1.MySQL的存储引擎。
(1)常用的存储引擎:InnoDB,MyISAM
(2)InnoDB支持事务处理、外键约束、占用空间比MyISAM大,适用于需要事物处理,更新删除频繁的应用场景。
(3)MyISAM不支持事物和外键约束,占用空间小,访问速度快,适用于需要事务处理,频繁查询的应用场景
2 MySQL的DML语句
(1)插入数据记录(INSERT):MySQL中INSERT INTO ...VALUES...语句可同时插入多条数据.
(2)更新数据记录(update)
(3)删除数据记录(DELETE):
3 MySQL中的DDL语句
(1)创建语句(CREATE)
(2)修改语句(ALTER)
(3)删除语句DROP\TRUNCATE;
4 MySQL中的select语句
(1)SELECT 语法:查询所有、部分、使用别名、空值、使用敞亮。
(2)where子句:对查询的结果进行限定
(3)ORDER BY子句,对查询结果进行排序
(4)LIMIT子句,对查询结果进行数量限定
5 MySQL的常用函数分类:聚合函数、字符串函数、时间日期函数、数学函数。
6 通配符是一类字符,他可以代替一个或多个真正的字符
7“-”和“%”分别匹配一个字符和多个字符
8 使用LIKE、BETWEEN、IN关键字,能够进行模糊查询
本章练习
1 举例说明MySQL中如何限定查询结果显示的条数
使用LIMIT SELECT * FROM student LIMIT,4,4;(从student中查询信息从第四条开始后四条显示)
2 举例说缪糕常用的聚合函数有哪几个
AVG(),COUNT(),MAX(),MIN(),SUM()
INSERT(str,pos,len,newstr),lower(str),UPPER(STR),SUBSTRING(str,num,len),LOCATE(substr,str).
CURDATE(),CURTIME(),NOW(),WEEK(date),YEAR(date),HOUR(time),DATEDIFF(date1,date2),ADDDATE(DATE,N)
3 已经知道一张银行开户表card包含卡号(cardId)、开户日期(openDate)、密码(password)等列,完成以下需求。
(1)使用SQL语句和时间函数获取本周开卡的信息
SELECT openDate FROM card WHERE WEEK(openDate)=WEEK(NOW());
(2)用户新卡的初始密码是随机生成的,现在出现一个问题:对于卡里面的字幕'O'和书子'0'、字幕'i'和书子‘1’用户反映看不请画出。于是公司决定,把存储在数据库中的所有字母'O'都改成0,所有字母i都改成1.
UPDATE card set password=REPLACE(REPLACE(password,'i',1),'O',0);
4 使用第二章中作业中创建的图书馆管理系统数据库,完成以下题目
(1)查询2002年以后出版的图书信息。要求:输出图书名称、图书编号、作者姓名、出版社、单价
SELECT bName,bId,author,pubComp,price FROM book WHERE pubComp>'2002-12-31';
(2)将借阅书籍数目按照从高到低进行排序,输出前三名读者信息,包括读者姓名,借阅书籍总数
SELECT rName,SUM(lendNum) FROM reader ORDER BY lendNum LIMIT 3;
(3)查询罚款金额的最高记录值
SELECT amount FROM PENALTY ORDER BY amount LIMIT 1;
5 在MySQL数据库中,方物信息表HouseInfo的结构如下
序号 | 字段名称 | 字段说明 | 类型 | 位数 | 备注 |
1 | HouseId | 序号 | INT | -- | 自动编号,主键 |
2 | HouseType | 房屋类型 | NVARCHAR | 30 | 如一室一厅等 |
3 | Area | 面积 | FLOAT | -- | 房屋建筑面积 |
4 | LandLord | 房主姓名 | NVARCHAR | 20 | |
5 | LandLordId | 身份证号 | NVARCHAR | 18 | 房主证件号码 |
6 | ExchangeType | 交易类型 | NVARCHAR | 2 | 只输入出租或出售 |
7 | LandlordTel | 联系电话 | VARCHAR | 20 | |
8 | Address | 地理位置 | NVARCHAR | 50 |
现在需要查询如下信息,请编写SQL语句实现
(1)房屋类型包含‘一厅’的房屋信息
(2)房主姓名为“于*令”的房屋信息,
(3)地理位置为‘解放区’的出租屋信息
(4)所有‘一室一厅’出售方的平均面积
CREATE TABLE HouseInfo(
HouseId INT(4) PRIMARY KEY AUTO_INCREMENT,
HouseType NVARCHAR(30) ,
Area FLOAT,
Landlord NVARCHAR(20),
LandLordId NVARCHAR(18),
ExchangeType ENUM('CZ','CS') NOT NULL,
LandLordTel VARCHAR(20),
Address NVARCHAR(50)
);
SELECT * FROM HouseInfo WHERE HouseType LIKE '%一厅%';
SELECT * FROM HouseINfo WHERE Landlord LIKE '于-令';
SELLECT *FROM HouseInfo WHERE Address LIKE '%解放区%';
SELELCT AVG(Area) FROM HouseInfo WHERE HouseType='一室一厅';