一、视图
视图是基于 SQL 语句的结果集的可视化的表,视图存放的是SQL查询语句,通过它会创建一张临时表,一旦与数据库断开连接,这个表就会被自动删除。视图和表的区别在于是否保存了实际的数据,表会存储实际的数据,而视图保存的是从表中取出数据所使用的SELECT语句。使用视图可以节省存储空间,提高效率,还可以保证数据的最新状态,因此应该将经常使用的SELECT语句创建成视图。
1、如何创建视图
CREATE VIEW 视图名称(<视图列名1>,<视图列名2>,......)
AS
SELECT 查询语句;
实例:我们按照性别汇总student表
CREATE VIEW 按性别汇总(性别,人数)
AS
SELECT 性别,count(*)
FROM student
GROUP BY 性别
点击运行后,视图这栏就会出现一个按照性别汇总的视图,创建好的视图会根据数据库的数据的变化自动更新,而且可以重复调用,非常方便。
2、定义好的视图如何使用?
SELECT 性别,人数
FROM 按性别汇总;-- 在from的子句中使用视图名称代替表名
3、使用视图的注意事项
- 避免在视图的基础上创建视图,多重视图会降低SQL的性能和效率
- 不能往视图里面插入数据
- 创建视图最好不要使用ORDER BY子句
4、删除视图
DROP VIEW 视图名称
二、子查询
- 子查询就是将用来定义视图的select语句直接用于from子句当中,还可以放在where子句中与in(子查询),all(子查询),any(子查询)配合使用。简单一点说就是把一个查询的结果在另一个查询中使用就叫做子查询。
- 子查询不会像视图那样保存在硬盘中,而是在select语句执行之后就消失了。因此,子查询就是一张一次性的视图。
- 在SQL运行顺序中会先执行子查询,然后再执行外部语句。
实例1:找出每个课程里成绩最低的学号
第一步:查出每门课程的最低成绩
第二步:在最低成绩中找出对应的学号
SELECT 学号,课程号,成绩
FROM score
WHERE 成绩 IN (
SELECT MIN(成绩)
FROM score
GROUP BY 课程号
);
实例2:哪些学生的成绩比课程0002的任意一个成绩高呢?
第一步:课程0002的成绩有哪些?
第二步:某个学生的成绩大于第一步里面的任意一个成绩,就符合条件
SELECT 学号,成绩
FROM score
WHERE 成绩 > ANY (
SELECT 成绩
FROM score
WHERE 课程号 = '0002'
);
大于课程0002中成绩的任意一个,其实就是要大于0002课程里成绩的最小值,所以也可以写成以下这样,运行结果是一样的:
SELECT 学号,成绩
FROM score
WHERE 成绩 > (
SELECT MIN(成绩)
FROM score
WHERE 课程号 = '0002'
);
此外,any(子查询)和some(子查询)是相同
实例3:哪些学生的成绩比课程0002的全部成绩里的都高呢?讲any换成all就可以解决问题
SELECT 学号,成绩
FROM score
WHERE 成绩 > ALL (
SELECT 成绩
FROM score
WHERE 课程号 = '0002'
);
比课程0002的全部成绩里的都高,意思就是要大于0002课程成绩的最大值,也可以写成以下查询语句:
SELECT 学号,成绩
FROM score
WHERE 成绩 > (
SELECT MAX(成绩)
FROM score
WHERE 课程号 = '0002'
);
子查询中的注意事项:
- 避免使用多层嵌套子查询,不容易看懂,也容易弄错
- 子查询最好重新命名子查询名称(子查询 AS 子查询名称)便于理解该子查询的用途和目的,类似于编程中的变量命名。
三、标量子查询
标量子查询是指子查询返回的是单一值(一个数字或一个字符串)的标量,也是子查询中最简单的返回形式。
实例1:选取大于平均成绩学生的学号和成绩,可能你会写成这样:
SELECT 学号,成绩
FROM score
WHERE 成绩 > AVG(成绩);
这样的写法程序会报错,因为where子句中后面不能使用汇总函数(avg、sum等)。正确的写法应该是:
SELECT 学号,成绩
FROM score
WHERE 成绩 > (
SELECT AVG(成绩)
FROM score
);
实例2:查询成绩介于差生(小于等于60分)的平均成绩和优等生(大于等于80分之间)平均成绩之间的学生有哪些?
SELECT 学号,成绩
FROM score
WHERE 成绩 BETWEEN
(SELECT AVG(成绩)
FROM score
WHERE 成绩 <= 60) AND
(SELECT AVG(成绩)
FROM score
WHERE 成绩 >= 80
);
实例3:任何使用单一值的地方都可以使用标量子查询
SELECT 学号,成绩,(SELECT AVG(成绩) FROM score) AS 平均成绩
FROM score;
四、关联子查询
关联子查询的基本逻辑:对于外部查询返回的每一行数据,内部查询都要执行一次。在关联子查询中是信息流是双向的。外部查询的每行数据传递一个值给子查询,然后子查询为每一行数据执行一次并返回它的记录。然后,外部查询根据子查询返回的记录做出决策。
在每个组里面比较,一般我们会用到关联子查询。我们先看一个实例:查找出每个课程中大于对应课程平均成绩的学生
SELECT 学号,课程号,成绩
FROM score AS s1 -- 同一表要使用别名,便于区分
where 成绩 > (
SELECT AVG(成绩)
FROM score AS s2 -- 同一表要使用别名,便于区分
WHERE s1.课程号 = s2.课程号 -- 关联条件,必须写在子查询中,并且s2仅在子查询里有效
GROUP BY 课程号
);
注意:关联条件一定要写在子查询中,上面例子中的(WHERE s1.课程号 = s2.课程号)
五、SQL常见基础函数
- 汇总函数
- 算数函数
- 字符串函数
- 日期函数
欢迎大家看看我写的其他MySQL基础知识系列文章,希望对你们有所帮助!
1、MySQL基础入门知识
假装在念书:MySQL基础知识—入门篇zhuanlan.zhihu.com
2、MySQL基础知识—简单查询
假装在念书:MySQL基础知识—简单查询zhuanlan.zhihu.com
3、MySQL基础知识—汇总查询
假装在念书:MySQL基础知识—汇总查询zhuanlan.zhihu.com
5、MySQL基础知识—多表查询
假装在念书:MySQL基础知识—多表查询zhuanlan.zhihu.com
六、实践出真知
现在我们打开SQLZOO网站:https://sqlzoo.net/,点击下面图片红色框选部分,开始习题练习,进行查询语句的练习:
第一题代码:
SELECT name
FROM world
WHERE population >
(SELECT population
FROM world
WHERE name='Russia');
第二题代码:
SELECT name FROM world
WHERE continent='Europe' and gdp/population >
(SELECT gdp/population FROM world
WHERE name = 'United Kingdom');
第三题代码:
SELECT name,continent
FROM world
WHERE continent IN (
SELECT continent
FROM world
WHERE name In ('Argentina','Australia')
)
ORDER BY name ;
第四题代码:
SELECT name,population
FROM world
WHERE population > (
SELECT population
FROM world
WHERE name = 'Canada')
and population <
(SELECT population
FROM world
WHERE name = 'Poland'
)
第五题代码:
SELECT name, concat(round(population*100/(select population from world where name='Germany')), '%') AS population
FROM world
WHERE continent = 'Europe';
第六题代码:
select name from world
where gdp > all
(select gdp from world
where continent = 'Europe' and gdp > 0);
第七题代码:
SELECT continent, name, area FROM world AS x
WHERE area >= ALL
(SELECT area FROM world AS y
WHERE y.continent=x.continent
AND area>0);
第八题代码:
select continent,name
from world as x
where name<= all (
select name
from world as y
where x.continent = y.continent
);
第九题代码:
select name,continent,population
from world as x
where 25000000 >= all(
select population
from world as y
where x.continent = y.continent);
第十题代码:
select name, continent
from world as x
where population > all
(select 3*population
from world as y
where y.continent=x.continent and x.name <> y.name);