1. 引入子查询
想用一个查询来完成两个查询的工作,我们可以在查询中添加子查询。
子查询是被另一个查询包围的查询,也可称为内层查询。而将子查询包围起来的那个查询则是外层查询。
外层查询利用子查询(内层查询)的结果进行查询。
比如:
第一个查询:
得到结果
第二个查询利用第一个查询的结果:
将这两个查询合并在一条语句里就是子查询的语法:
SELECT mc.first_name, mc.last_name, mc.phone, jc.title
FROM job_current AS jc
NATURAL JOIN my_contacts AS mc
WHERE jc.title
IN (SELECT title FROM job_listings);
子查询写在括号里,并且没有自己单独结尾的分号。
2.子查询问题分解
子查询的难点在于确定是否需要子查询以及如何确定哪部分作为子查询,哪部分作为外层查询。
假设数据表:my_contacts中存储联系人基本信息,job_current中存储人们当前工作相关信息。
假设一个问题:在我所有的联络人里,谁赚钱最多?
分解问题:重新描述这个问题换成表与列的名称。
(1)“谁”表示需要my_ocntacts里的first_name和last_name列。
(2)“钱最多”表示需要job_current表的MAX(salary)值。
将上面两部分写成查询语句
(1)找出姓与名
SELECT mc.first_name, mc.last_name
FROM my_contacts AS mc;
(2)找出最高薪水
SELECT MAX(salary) FROM job_current;
(3)找出串起两个查询的方式
我们不仅需要my_contacts里记载的人名,还需要知道他们的薪水,才能比较出最高的薪资(MAX(salary))。我们需要一个内联接来找出每个人的薪资信息。
SELECT mc.first_name, mc.last_name, jc.salary
FROM my_contacts AS mc
NATURAL JOIN job_current AS jc;
(4)最后假设WHERE子句以连接(2)(3)两段查询
SELECT mc.first_name, mc.last_name, jc.salary
FROM my_contacts AS mc
NATURAL JOIN job_current AS jc
WHERE jc.salary =
(SELECT MAX(salary) FROM job_current jc));
3.子查询可以作为欲选取的列返回。
查找姓、名与相应的洲名。
SELECT mc.first_name, mc.last_name,
(SELECT state FROM zip_code WHERE mc.zip_code = zip_code) AS state
FROM my_contacts;
上述括号中的子查询只是单纯的从zip_code中比对出邮政编码(zip_code)与相应的洲名。
如果子查询放在SELECT语句中用于表示某个欲选取的列,则一次只能从一列返回一个值。而整个查询也跟着返回一行。
下面是查询结果:
4.子查询分类
非关联子查询
如果子查询可以独立运行且不会引用外层查询的任何结果,即称为非关联子查询。
前面我们提到的子查询都是非管理子查询。
软件先处理子查询(内层查询),查询结果再用于外层查询的WHERE子句,但是内层查询完全不需要依赖外层查询的值,它本身就是一个可以完全独立运行的查询。
关联子查询
关联子查询是指内层查询的解析需要依赖外层查询的结果。
如假设问题:my_contacts里的每个人各有几项兴趣,然后返回具有三项兴趣的人。
SELECT mc.first_name, mc.last_name
FROM my_contacts AS mc
WHERE
3 = (SELECT COUNT(*) FROM contact_interest
WHERE contact_id = mc.contact_id);
子查询中contact_id = mc.contact_id依赖外层查询的结果,外层查询必须先执行完后,我们才能知道mc.contact_id的值。
EXISTS、NOT EXISTS
(1)NOT EXIST
关联子查询常见用法是找出所有外层查询结果里不存在于关联表里的记录。
如:想知道my_contacts 里的目前不在job_current表中的人和他们的邮件地址。
SELECT mc.first_name, mc.last_name, mc.email
FROM my_contacts mc
WHERE NOT EXISTS
(SELECT * FROM job_current jc WHERE mc.contact_id = jc.contact_id);
NOT EXIST负责从my_contacts表中找出姓名和邮件地址,他们都为列在job_current 表中。
(2)NOT EXIST
如:下列查询将返回来自my_contacts表的数据,其中contact_id 曾出现在contact_interest表中。
SELECT mc.first_name, mc.last_name, mc.email
FROM my_contacts mc
WHERE EXISTS
(SELECT * FROM contact_interest ci WHERE mc.contact_id = ci.contact_id);
EXIST 负责从my_contacts 表中找出姓名和邮件地址,这些记录曾出现在contace_interest表中。