在搞清楚简单查询以后,我们现在开始学习复杂查询,还是以之前的饭堂仓库为例子,简单查询就是从仓库里面取出胡萝卜,而复杂查询就是从全部胡萝卜里面挑出上周买的萝卜。
一、子查询&视图
那么我们要怎么取胡萝卜呢?首先我们可以将仓库里面的全部胡萝卜都找出来,在从里面挑出上周五购买的,为了方便理解,我们可以像这样写出伪代码(我们将菜品种类设为列)
SELECT 菜品种类
FROM(SELECT 菜品种类,购买日期
FROM 仓库
WHERE 菜品种类 = 胡萝卜)AS 库存胡萝卜
WHERE 购买日期 = 上周五
这样的话,由于SQL会先执行子查询,因此我们先会把全部胡萝卜取出来,然后在主查询中将上周五的胡萝卜全部挑出来。
这时候,由于饭堂老板特别喜欢吃新鲜胡萝卜,我们每周都需要将本周的新鲜胡萝卜挑出来,但每周都重新安排一次工作太麻烦了,应该怎么样才能找个什么套路来简化工作呢?这时我们就可以使用视图功能,当我们建立了视图,每次执行它的时候,就相当于让仓库管理员按照设定好的套路将我们需要的材料取出来
CREATE VIEW 视图名(列1,列2...)
AS SELECT (列1,列2...)
FROM ...;
我们把需要的套路写下来交给管理员,这样我们每次让管理员(数据库管理工具)按照定好的套路执行就可以了。
二、标量子查询
过了一段时间老板已经不满足于吃新鲜胡萝卜了,为了体现出自己的身份,决定要吃长度比平均长度长的胡萝卜,这时候我们应该怎么办呢?在计算之前我们是不知道胡萝卜的平均长度的。这时候我们我们就需要用到标量子查询了,标量子查询能返回一个特定值。我们可以这样处理,假设我们已经有了每根胡萝卜的长度放在 长度 列里面,这时可以先求出胡萝卜的平均长度,然后在筛选出长度大于平均长度的胡萝卜,伪代码可以这样子写
SELECT 菜品种类
FROM 仓库
WHERE 菜品种类 = 胡萝卜
AND 长度 >(SELECT AVG(长度)
FROM 仓库
WHERE 菜品种类 = 胡萝卜)
这样子查询中就能先返回平均胡萝卜长度,然后在和中的胡萝卜进行对比,挑出比平均值长的胡萝卜了。
这种子查询主要用到我们需要将筛选条件设置为一个未知值得时候使用
三、关联子查询
又过了一段时间,老板已经不满足于只吃胡萝卜了,决定还要吃点黄瓜,苦瓜,并且都要比平均长度长。按照之前的逻辑我们只要在子查询里面加一个GROUP BY 菜品种类就可以了,但是当我们将GROUP BY 加到代码里面的时候我们会发现代码会报错,这时因为,使用了GROUP BY 以后子函数会返回一个列,里面有胡萝卜,黄瓜,苦瓜的平均长度,SQL运行的时候会把每一行的值和子函数返回的值进行比较。由于返回的是多个种类菜品的平均值这样就无法比较大小了。这时候就需要关联子查询来让子函数返回对应菜品的平均长度,我们可以将菜品关联起来以确保能返回正确的值。
SELECT 菜品种类
FROM 仓库 AS 仓库1
WHERE 菜品种类 in ('胡萝卜','黄瓜','苦瓜')
AND 长度 >(SELECT AVG(长度)
FROM 仓库 AS 仓库2
WHERE 仓库1.菜品种类 = 仓库2.菜品种类)
这样老板就又吃到了想要的菜,我们又离升职加薪,迎娶白富美近了一步。
四、题目练习
题目来自SQLZOO
SELECT within SELECT Tutorial/zhsqlzoo.net第五题(子查询):
Germany德國(人口8000萬),在Europe歐洲國家的人口最多。Austria奧地利(人口850萬)擁有德國總人口的11%。
顯示歐洲的國家名稱name和每個國家的人口population。以德國的人口的百分比作人口顯示。
SELECT name,CONCAT(ROUND((population/(SELECT population
FROM world
WHERE name = 'Germany')*100),0),'%')
FROM world
WHERE continent = 'Europe'
第六题(标量子查询):
哪些國家的GDP比Europe歐洲的全部國家都要高呢? [只需列出name。] (有些國家的記錄中,GDP是NULL,沒有填入資料的。)
SELECT name
FROM world
WHERE gdp >
ALL(SELECT gdp
FROM world
WHERE continent = 'Europe'
AND gdp is not NULL)
第九题(关联子查询):
找出洲份,當中全部國家都有少於或等於 25000000 人口. 在這些洲份中,列出國家名字name,continent洲份和popation人口。
SELECT name,continent,population
FROM world as w1
WHERE 25000000 >ALL(SELECT population
FROM world as w2
WHERE w1.continent = w2.continent)