DQL(Data Query language)数据查询语言是数据库最核心的语言,最重要的语句,同样也是使用频率最高的语句,所有的查询操作都使用它,并且在简单的查询和复杂的查询中,他都能做。
在学习之前,我们需要明确一下关于查询的关键字以及语法:
SELECT [ALL | DISTINCT]
{* | table.* | [table.filed01[AS alias10][,table.filed01[AS alias10]][,...]]}
FROM table_name01 [AS table_alias]
[LEFT | RIGHT | INNER JOIN table_name02] -- 联合查询
[WHERE ...] -- 指定结果需满足的条件
[GROUP BY ...] -- 指定结果按照哪几个字段来分组
[HAVING ...] -- 过滤分组的记录必须满足的次要条件
[ORDER BY ...] -- 指定查询记录按一个或多个条件排序
-- 指定查询的记录从哪条到哪条
[LIMIT {[offest,]ROW_COUNT | row_countOFFSET OFFSET}];
上述代码中,[]代表着可选语句,{}代表着必选语句,并且语句之间的排序顺序不能更换!
大致了解了基本语法过后,我们首先创建一个数据库,用于之后的查询——
-- 创建一个school数据库
USE `school`;-- 创建学生表
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`(
`studentno` INT NOT NULL COMMENT '学号',
`loginpwd` VARCHAR(20) DEFAULT NULL,
`studentname` VARCHAR(20) DEFAULT NULL COMMENT '学生姓名',
`sex` TINYINT DEFAULT NULL COMMENT '性别,0或1',
`gradeid` INT DEFAULT NULL COMMENT '年级编号',
`phone` VARCHAR(50) NOT NULL COMMENT '联系电话,允许为空',
`address` VARCHAR(255) NOT NULL COMMENT '地址,允许为空',
`borndate` DATETIME DEFAULT NULL COMMENT '出生时间',
`email` VARCHAR (50) NOT NULL COMMENT '邮箱账号允许为空',
`identitycard` VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
PRIMARY KEY (`studentno`),
UNIQUE KEY (`identitycard`),
KEY `email` (`email`)
)ENGINE=MYISAM DEFAULT CHARSET=utf8mb4;
-- 创建年级表
DROP TABLE IF EXISTS `grade`;
CREATE TABLE `grade`(
`gradeid` INT NOT NULL AUTO_INCREMENT COMMENT '年级编号',
`gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',
PRIMARY KEY (`gradeid`)
) ENGINE=INNODB AUTO_INCREMENT = 6 DEFAULT CHARSET = utf8mb4;
-- 创建科目表
DROP TABLE IF EXISTS `subject`;
CREATE TABLE `subject`(
`subjectno`INT NOT NULL AUTO_INCREMENT COMMENT '课程编号',
`subjectname` VARCHAR(50) DEFAULT NULL COMMENT '课程名称',
`classhour` INT DEFAULT NULL COMMENT '学时',
`gradeid` INT DEFAULT NULL COMMENT '年级编号',
PRIMARY KEY (`subjectno`)
)ENGINE = INNODB AUTO_INCREMENT = 19 DEFAULT CHARSET = utf8mb4;
-- 创建成绩表
DROP TABLE IF EXISTS `result`;
CREATE TABLE `result`(
`studentno` INT NOT NULL COMMENT '学号',
`subjectno` INT NOT NULL COMMENT '课程编号',
`examdate` DATETIME NOT NULL COMMENT '考试日期',
`studentresult` INT NOT NULL COMMENT '考试成绩',
KEY (`subjectno`)
)ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
-- 插入学生数据(这里仅添加了小部分数据,其余自行添加)
INSERT INTO `student` (`studentno`,`loginpwd`,`studentname`,`sex`,`gradeid`,`phone`,`address`,`borndate`,`email`,`identitycard`)
VALUES
(1001,'123456','张伟',0,2,'13800001234','北京朝阳','1980-1-1','[email protected]','123456198262611234'),
(1002,'123456','李宁',1,3,'13800002222','广东梅州','1990-1-1','[email protected]','123299919001011273'),
(1003,'123456','陈真',1,3,'13800002222','广东深圳','1990-1-1','[email protected]','121626199001011233'),
(1004,'123456','王伟',1,3,'13800002222','广东广州','1990-1-1','[email protected]','123452999001011233'),
(1005,'123456','赵涵',1,3,'13800002222','陕西西安','1990-1-1','[email protected]','129556191611101123'),
(1006,'123456','章仪',1,3,'13800002222','广东云浮','1990-1-1','[email protected]','123456199001161233');
-- 插入年级数据
INSERT INTO `grade` (`gradeid`,`gradename`) VALUES(1,'大一'),(2,'大二'),(3,'大三'),(4,'大四'),(5,'预科班');
-- 插入科目数据
INSERT INTO `subject`(`subjectno`,`subjectname`,`classhour`,`gradeid`)VALUES
(1,'高等数学-1',110,1),
(2,'高等数学-2',110,2),
(3,'高等数学-3',100,3),
(4,'高等数学-4',130,4),
(5,'C语言-1',110,1),
(6,'C语言-2',110,2),
(7,'C语言-3',100,3),
(8,'C语言-4',130,4),
(9,'Java程序设计-1',110,1),
(10,'Java程序设计-2',110,2),
(11,'Java程序设计-3',100,3),
(12,'Java程序设计-4',130,4),
(13,'数据库结构-1',110,1),
(14,'数据库结构-2',110,2),
(15,'数据库结构-3',100,3),
(16,'数据库结构-4',130,4),
(17,'C#基础',130,1);
-- 剩余的表数据(例如result表)可以自己随意添加,添加的数据可少可多,只需要满足学习需求即可
基本查询语句
-- 查询student表所有字段的数据
SELECT * FROM `student`
-- 查询subject表指定字段的数据
SELECT `subjectno`,`subjectname` FROM `subject`
-- 查询subject表指定字段的数据,并为这组数据起一个别名(AS)
SELECT `subjectno` AS 课程编号,`subjectname` AS 课程名 FROM `subject`
-- 查询subject表指定字段的数据,并对数据名进行字符组合(Concat(sub A,sub B))
SELECT CONCAT('必修:',`subjectname`) AS 新课程名 FROM `subject`
去重 distinct
假设我们需要查询有哪些同学参与了考试,于是我们对result表进行查询操作!
-- 查询result表中的学号字段
SELECT `subjectno` FROM `result`
运行之后发现,得到的数据有大量重复数据,不太符合我们的需求,我们需要去掉重复的数据!
-- 查询result表中的学号字段并略去重复的数据
SELECT DISTINCT `subjectno` FROM `result`
数据库的列(表达式)
Select语句不仅可以查询表字段的数据,还可以进行其他查询操作!
-- 查询当前MySQL版本
SELECT VERSION()
-- 获得计算结果
SELECT 100*3-5 AS 计算结果
-- 查询当前自增步长
SELECT @@auto_increment_increment
-- 查询result表中学生成绩字段,并为所有的学生考试成绩+1分
SELECT `studentno`,`studentresult`+1 AS 新成绩 FROM `result`
数据库中的表达式:文本值,列,Null,函数,计算表达式,系统变量…
作用:检索数据中符合条件的值
-- 查询result表中成绩为[80-100]之间的学生
SELECT `studentno`,`studentresult` FROM `result` WHERE `studentresult` >= 80 AND `studentresult` <= 100
-- 模糊查询
SELECT `studentno`,`studentresult` FROM `result` WHERE `studentresult` BETWEEN 80 AND 100
-- 查询result表中学生学号为1000和1002的学生
SELECT `studentno`,`studentresult` FROM `result` WHERE `studentno`=1000 OR `studentno`=1002
-- 查询result表中学生学号不为1000的学生
SELECT `studentno`,`studentresult` FROM `result` WHERE NOT `studentno`=1000
在上述语句中,and、or、not关键字都可以替换为对应的&&、||、!逻辑运算符,不过这边建议使用关键字,这样的目的是为了提升代码的可读性。
模糊查询:比较运算符
操作符 | 描述 |
---|---|
IS NULL | 如果操作值为NULL,则返回true |
IS NOT NULL | 如果操作值不为NULL,则返回true |
BETWEEN AND | 如果操作值A在范围[B,C]之间,则返回true |
LIKE | 如果操作值A可以和B匹配(SQL匹配),则返回true |
IN | 如果操作值A在某组数据之中,则返回true |
LIKE操作符:
-- 查询student表中所有姓张的同学(使用like作为操作符查询,将会配合百分号%以及下划线_来使用)
-- %(代表0~任意个字符);_(代表1个字符)
SELECT `studentno`,`studentname` FROM `student` WHERE `studentname` LIKE '张%'
-- 查询student表中姓刘且是单字名的同学
SELECT `studentno`,`studentname` FROM `student` WHERE `studentname` LIKE '张_'
-- 查询student表中姓刘且是双字名的同学
SELECT `studentno`,`studentname` FROM `student` WHERE `studentname` LIKE '张__'
-- 查询student表中名字带“伟”字的同学
SELECT `studentno`,`studentname` FROM `student` WHERE `studentname` LIKE '%伟%'
IN操作符:
-- 查询student表中学号为1001,1002,1003的学生
SELECT `studentno`,`studentname` FROM `student` WHERE `studentno` IN(1001,1002,1003)
-- 查询student表中地址为广东广州的学生
SELECT `studentname`,`address` FROM `student` WHERE `address` IN('广东广州')
IS NOT和IS NOT NULL操作符:
-- 查询student表中地址为空的学生
SELECT `studentname`,`address` FROM `student` WHERE `address` IS NULL OR `address`=''
-- 查询student表中出生日期不为空的学生
SELECT `studentname`,`borndate` FROM `student` WHERE `borndate` IS NOT NULL
Join
-- 查询学生编号,以及相匹配的学生姓名、课程编号以及考试成绩
/*
首先可以明确了解到,这些字段来自于不同的表,所以我们需要使用连接查询
先确定要使用7种连接查询方式的哪一种,再确立交叉点
*/
-- inner join
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s
INNER JOIN `result` AS r
ON s.`studentno` = r.`studentno`
-- left join
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s
LEFT JOIN `result` AS r
ON s.`studentno` = r.`studentno`
-- right join
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s
RIGHT JOIN `result` AS r
ON s.`studentno` = r.`studentno`
从查询的结果来看,我们可以观察到,使用inner join,如果表中至少有一个匹配,那么就会返回行,换句话说,只会返回result表中有成绩的学生(学生编号相匹配的行),当使用left join的时候,即使右表中没有匹配,也会返回左表中所有的值(无论有没有成绩的学生行都会返回),当使用right join的时候,即使左表中没有匹配,也会返回右表中所有的值。
注意:在inner join中,将on替换为where一样可以得到结果,但是在left join中,却会报错,这是因为where条件在临时表生成之后,会再对临时表进行过滤的条件,这时已经失去了left join的含义(必须返回左表中所有的值),在MySQL语句中,join on为连接查询,where为等值查询,这边还是更加建议使用规范的join on语句哟~
-- 查询缺考的同学
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s
LEFT JOIN `result` AS r
ON s.`studentno` = r.`studentno`
WHERE `studentresult` IS NULL
操作 | 描述 |
---|---|
inner join | 如果表中至少有一个匹配,那么就会返回行 |
left join | 即使右表中没有匹配,也会返回左表中所有的值 |
right join | 即使左表中没有匹配,也会返回右表中所有的值 |
当对多个表进行查询的时候,先要明确需要查询的字段位于哪几个表中,并且确定Join on连接方式和交叉条件!
-- 查询有考试成绩的学生编号,以及相匹配的学生姓名、课程名称以及考试成绩
SELECT r.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` AS s
RIGHT JOIN `result` AS r
ON r.`studentno` = s.`studentno`
INNER JOIN `subject` AS sub
ON r.`subjectno` = sub.`subjectno`
-- 查询参加了高等数学-1科目的学生编号、学生姓名、以及考试成绩
SELECT s.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` AS s
INNER JOIN `result` AS r
ON s.`studentno` = r.`studentno`
INNER JOIN `subject` AS sub
ON r.`subjectno` = sub.`subjectno`
WHERE `subjectname` = '高等数学-1'
在熟悉查询操作之后,我们可以在操作基础上增加一些其他的操作,例如修改、删除!
假设此时有两张表,一张表为学生表Student,记录学生的学号Sno、学生的年级Grade和姓名Sname,另一张表为成绩表sc,记录学生的学号Sno、学生的课程Course和学生的成绩Score,我们需要将年级为 “高二” 的学生的成绩都置为0,为了完成这个操作,我们需要将查询和修改这两个操作联合起来~
UPDATE `student` AS stu
INNER JOIN `sc` AS s
ON stu.`Sno` = s.`Sno`
SET s.`Grade`=0 WHERE stu.`Grade` IN('高二')
自连接其实说白了就是将一张表拆成两张一样的表,可以简单的理解为一张表内涵盖了所有的学科,而我们需要的就是将这张表里的主学科和其下的分支学科拆分成两张表。
CREATE TABLE `category`(
`categoryid` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主题id',
`pid` INT(3) NOT NULL COMMENT '父id',
`categoryname` VARCHAR(50) NOT NULL COMMENT '主题名字',
PRIMARY KEY (`categoryid`)
)ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb3;
INSERT INTO `category` (`categoryid`, `pid`, `categoryname`)
VALUES (2, 1, '信息技术'),
(3, 1, '软件开发'),
(5, 1, '美术设计'),
(4, 3, '数据库'),
(8, 2, '办公信息'),
(6, 3, 'web开发'),
(7, 5, 'ps技术');
以上代码我们可以得到一张简单的表,这里我们可以理解为父id就是一棵树的层数,当父id为1时,代表着位于树的顶点,也就是我们所说的主学科,我们可以先将这些“主学科”划分为父类表:
pid | categoryid | ategoryname |
---|---|---|
1 | 2 | 信息技术 |
1 | 3 | 软件开发 |
1 | 5 | 美术设计 |
而剩下的,我们可以根据主题id(categoryid),查询主学科下所对应的分支学科,也就是看其pid是否与父类表中的categoryid相匹配,这样我们就可以得到这些‘“分支学科”所构成的子类表:
pid | categoryid | ategoryname |
---|---|---|
2 | 8 | 办公信息 |
3 | 4 | 数据库 |
3 | 6 | web开发 |
5 | 7 | ps技术 |
结果已经呼之欲出了,我们需要得到一个父类表和子类表相匹配的表(主学科对应着分支学科的表),也就是如下所述:
父类 | 子类 |
---|---|
信息技术 | 办公信息 |
软件开发 | 数据库 |
软件开发 | web开发 |
美术设计 | ps技术 |
注意,我们对一张表进行自连接操作时,需要起别名来区分父类与子类,并且where判断条件为父类的父id等于子类的主题id!
SELECT a.`categoryname` AS '父栏目',b.`categoryname` AS '子栏目'
FROM `category` AS a,`category` AS b
WHERE a.`categoryid` = b.`pid`
排序
MySQL的排序关键字为order by,后面紧跟需要进行排序的字段,排序无非就两种方式,一种是升序,使用关键字ASC来描述,另一种是降序,使用关键字DESC来描述。
-- 排序order by(ASC代表升序,DESC代表降序)
-- 查询参加了高等数学-1科目的学生编号、学生姓名、以及考试成绩,并将成绩降序排序
SELECT s.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` AS s
INNER JOIN `result` AS r
ON s.`studentno` = r.`studentno`
INNER JOIN `subject` AS sub
ON r.`subjectno` = sub.`subjectno`
WHERE `subjectname` = '高等数学-1'
ORDER BY `studentresult` DESC
分页
首先我们需要思考,为什么需要分页?
因为数据是非常庞大的,无法一时间之内全部加载出来,所以我们需要一个方式,将数据截成若干部分,每次只呈现其中一部分,只要通过翻页,就可以刷新数据至下一部分,非常有效地缓解了数据库的压力,也给人更加良好的浏览体验。
现如今除了翻页模式,还有一种模式叫做瀑布流,本质上也是限制数据的加载,我们可以在百度图片的网页上,一直向下滑动,数据会不断加载,现如今,采用这种方式的网页非常之多,实际效果可以看到,用户往往会更加喜欢这种一直向下滑,并且不断加载的模式,本人也是,比分页模式更具有沉浸感!
MySQL的排序关键字为limit,后面紧跟两个参数,第一个参数代表着查询起始页的初始下标,第二个参数为页面大小
SELECT * FROM `subject`
LIMIT 0,5
以上代码我们就可以查询到第一页的数据,一共五条,起始页为0,而我们要查询第二页的数据,则需要在起始页的初始下标加上页面大小,也就是0 + 5 = 5:
SELECT * FROM `subject`
LIMIT 5,5
观察上述代码,我们就可以发现一个规律:当我们需要查询第n页的数据时,起始页的初始下标 =(n - 1)* pageSize,其中pageSize为页面大小,n为当前页数,总页数 = 数据总数 / 页面大小!
结合分页和排序,我们可以进行一些较为复杂的查询操作,例如:
-- 查询高等数学-1课程成绩排名前十,并且分数大于80的学生(学生编号、学生姓名、课程名称、考试成绩)
SELECT s.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` AS s
INNER JOIN `result` AS r
ON s.`studentno` = r.`studentno`
INNER JOIN `subject` AS sub
ON r.`subjectno` = sub.`subjectno`
WHERE `subjectname` = '高等数学-1' AND `studentresult` >= 80
ORDER BY `studentresult` DESC
LIMIT 0,10
假如现在我们有一个需求,是求subject表中,所有课程的平均分,最高分以及最低分,于是我们可以通过聚合函数来完成这次需求:
-- 查询不同课程的平均分,最高分,最低分
SELECT any_value(`subjectname`),AVG(`studentresult`),MIN(`studentresult`),MAX(`studentresult`)
FROM `result` AS r
INNER JOIN `subject` AS s
ON r.`subjectno` = s.`subjectno`
值得注意的是:低版本的MySQL并不需要添加any_value()函数,而高版本的MySQL提供了any_value()函数来抑ONLY_FULL_GROUP_BY值被拒绝,可是,我们仍然只能得到第一组的数据,而我们需要的则是所有考试科目的数据,于是就有了分组!
SELECT `subjectname`,AVG(`studentresult`),MIN(`studentresult`),MAX(`studentresult`)
FROM `result` AS r
INNER JOIN `subject` AS s
ON r.`subjectno` = s.`subjectno`
GROUP BY r.`subjectno`
通过关键字group by关键字来对数据进行分组,这样我们就可以得到完整的数据!
但此时,假设我们在题目之上增加了平均分大于60的数据这一个限制条件,通过尝试,可以发现使用where子句会报错,仔细观察select语句格式,可以看到关键字having可以用于描述过滤分组的记录必须满足的次要条件!
HAVING AVG(`studentresult`) > 60
Tips:这项内容建议先学习了聚合函数再回过头来学习!
子查询的本质上只是在where判断语句中嵌套了一个select语句(子查询语句),简单而言,就是将查询的问题拆分成了两个问题,分别进行查询!
假设我们需要查询参与了高等数学-1考试的学生,而所查询的字段仅需要学生编号、课程编号、还有考试成绩这几项在result表中就有的字段,而联表查询固然可以得到结果,但是为了避免多余的查询,我们并不想将进行表联结,这个时候我们就可以使用子查询而不需要联表查询便可得到结果:
-- 查询查询参与了高等数学-1考试的学生(学生编号、课程编号、考试成绩)
SELECT `studentno`,`subjectno`,`studentresult`
FROM `result`
WHERE `subjectno` = (
SELECT `subjectno` FROM `subject` WHERE `subjectname` = '高等数学-1'
)
熟练子查询之后,我们还可以进行更加复杂的查询操作,但如果你的联表查询使用的更加准确且更加顺手,这边还是建议使用联表查询!
-- 查询参与了高等数学-1考试的学生(学生编号、课程名称、考试成绩)
-- 进行降序排序
SELECT `studentno`,`subjectname`,`studentresult`
FROM `result` AS r
INNER JOIN `subject` AS sub
ON r.`subjectno` = sub.`subjectno`
WHERE r.`subjectno` = (
SELECT `subjectno` FROM `subject` WHERE `subjectname` = '高等数学-1'
)
ORDER BY `studentresult` DESC
-- 查询参与了高等数学-1考试且分数在60分以上的学生(学生编号、学生姓名)
-- 嵌套
SELECT `studentno`,`studentname` FROM `student` WHERE `studentno` IN (
SELECT `studentno` FROM `result` WHERE `studentresult` >= 60 AND `subjectno` = (
SELECT `subjectno` FROM `subject` WHERE `subjectname` = '高等数学-1'
)
)
首先提供一个官方网页,收录了几乎所有的MySQL函数,当对某个函数不熟悉或者忘记的时候,可以直接前往网页翻阅:
https://dev.mysql.com/doc/refman/8.0/en/built-in-function-reference.html
-- 数学函数
SELECT ABS(-8) -- 绝对值
SELECT CEILING(9.4) -- 向上取整
SELECT FLOOR(9.4) -- 向下取整
SELECT RAND() -- 返回一个[0,1)的随机浮点数
SELECT SIGN(10) -- 返回参数的符号(负数返回-1,正数返回1,0返回0)
-- 字符串函数
-- 返回字符串长度(泰戈尔《烧毁记忆》)
SELECT CHAR_LENGTH('有一个夜晚,我烧毁了所有的记忆,从此我的梦就透明了。')
SELECT CONCAT('A','y','in') -- 拼接字符串
-- 插入字符串(两个参数分别是在第几个字符开始插入和插入的字符串长度)
-- 该函数会替换字符串
SELECT INSERT('Hello,past time!',1,5,'Goodbye')
SELECT UPPER('Ayin') -- 全转为大写字母
SELECT LOWER('Ayin') -- 全转为小写字母
SELECT INSTR('Ayin','A') -- 返回第一次出现子串的索引
SELECT REPLACE('世界以歌颂自由','自由','史诗') -- 替换指定字符串
-- 返回指定的子字符串(两个参数分别是源字符串截取的位置和截取的长度)
-- 泰戈尔《飞鸟集》
SELECT SUBSTR('If you shed tears when you miss the sun, you also miss the stars.',42,24)
SELECT REVERSE("为所欲为") -- 反转字符串
-- 将student表中的王伟替换为李伟
SELECT REPLACE(`studentname`,'王','李') FROM `student`
WHERE `studentname` = '王伟'
-- 时间和日期函数
SELECT CURRENT_DATE() -- 返回当前日期
SELECT CURDATE() -- 返回当前日期
SELECT NOW() -- 返回当前具体时间
SELECT LOCALTIME() -- 返回本地时间
SELECT SYSDATE() -- 返回系统时间
SELECT YEAR(NOW()) -- 返回当前年份(year\month\day\minute\second)
-- 系统
SELECT SYSTEM_USER() -- 返回系统用户
SELECT USER()
SELECT VERSION() -- 返回当前MySQL版本号
函数名称 | 描述 |
---|---|
count | 记数 |
sum | 求和 |
avg | 平均值 |
max | 最大值 |
min | 最小值 |
-- 统计该列字段在表中出现的次数,会忽略所有的null值
SELECT COUNT(`borndate`) FROM `student`
-- 包括了所有的列,相当于行数,在统计结果的时候,不会忽略NULL
SELECT COUNT(*) FROM `student`
-- 会统计表中的所有的记录数,不会忽略NULL,包含字段为null 的记录。
SELECT COUNT(1) FROM `student`
如果列名为主键,count(列名)会比count(1)快 ;如果列名不为主键,count(1)会比count(列名)快
若表多个列并且没有主键,则 count(1) 的执行效率优于 count(*),若表有主键,则 select count(主键)的执行效率是最优的。
若表只有一个字段,则 select count(*)最优。
所以实际业务中一般用count(1)比较普遍,但是如果需要聚合多个列,则用count(列名)比较合适。
SELECT SUM(`studentresult`) FROM `result` -- 求和
SELECT AVG(`studentresult`) FROM `result` -- 平均值
SELECT MIN(`studentresult`) FROM `result` -- 最小值
SELECT MAX(`studentresult`) FROM `result` -- 最大值
**MD5信息摘要算法 **(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。这套算法的程序在 RFC 1321 标准中被加以规范。
1996年后该算法被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA-2。
2004年,证实MD5算法无法防止碰撞(collision),因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。
1992年8月,罗纳德·李维斯特向互联网工程任务组(IETF)提交了一份重要文件,描述了这种算法的原理。由于这种算法的公开性和安全性,在90年代被广泛使用在各种程序语言中,用以确保资料传递无误等。
MD5由MD4、MD3、MD2改进而来,主要增强算法复杂度和不可逆性。MD5算法因其普遍、稳定、快速的特点,仍广泛应用于普通数据的加密保护领域。
我们现在可以看到所谓的MD5破解网站,原理是网站相当于一个字典,把常见密码经过MD5加密后的值都录入了字典内,如果密码较为简单,且字典里正好有该密码经过MD5加密后的值,便返回加密前的值!不过MD5可以进行多层加密,如果一串密码进过几百层加密什么的,这些网页估计也没辙。
-- 测试MD5加密
CREATE TABLE IF NOT EXISTS `testmd5`(
`id` INT(2) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4\
INSERT INTO `testmd5` VALUES
(1,'张三','123456'),
(2,'李四','123456'),
(3,'王五','123456')
-- MD5加密
UPDATE `testmd5` SET pwd=MD5(pwd)
-- 插入时加密
INSERT INTO `testmd5` VALUES(4,'吴六',MD5('123456'))
注意:这里设置的密码初始长度并不能太短,否则会报错‘data too long for column ‘pwd’ at row 1’!