第九章:子查询
9.1:子查询的基本使用
-  子查询的基本语法结构 SELECT .... FROM .... WHERE expr operator (SELECT ... FROM ... WHERE ...);- 子查询(内查询)在主查询之前一次执行完成。
- 子查询的结果被主查询(外查询)使用。
- 注意事项 
    - 子查询要包含在括号内。
- 将子查询放在比较条件的右侧。
- 单行操作符对应单行子查询,多行操作符对应多行子查询
 
 
-  子查询的分类 -  分类方式1 我们按内查询的结果返回一条还是多条记录,将子查询分为单行子查询、多行子查询。 
-  分类方式2  我们按内查询是否被执行多次,将子查询划分为相关(或关联)子查询和不相关(或非关联)子查询。  子查询从数据表中查询了数据结果,如果这个数据结果只执行一次,然后这个数据结果作为主查询的条件进行执行,那么这样的子查询叫做不相关子查询。  同样,如果子查询需要执行多次,即采用循环的方式,先从外部查询开始,每次都传入子查询进行查询,然后再将结果反馈给外部,这种嵌套的执行方式就称为相关子查询。 
 
-  
9.2:单行子查询
-  单行比较操作符 操作符 含义 =equal to>greater than>=greater than or equal to<less than<=less than or equal to<>not equal to
-  代码示例 -  返回 job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资。SELECT last_name, job_id,salary FROM employees WHERE job_id = ( SELECT job_id FROM employees WHERE employee_id = 141 ) AND salary > ( SELECT salary FROM employees WHERE employee_id = 143 );
-  返回公司工资最少的员工的 last_name、job_id和salary。SELECT last_name, job_id, salary FROM employees WHERE salary = ( SELECT MIN(salary) FROM employees );
 
-  
-  HAVING中的子查询首先执行子查询,向主查询中的 HAVING子句返回结果。-  查询最低工资大于110号部门最低工资的部门id和其最低工资 SELECT department_id, MIN(salary) FROM employees WHERE department_id IS NOT NULL GROUP BY department_id HAVING MIN(salary) > ( SELECT MIN(salary) FROM employees WHERE department_id = 110 );
 
-  
-  CASE中的子查询-  显示员工的 employee_id、last_name和location。其中,若员工department_id与location_id为1800的department_id相同,则location为Canada,其余则为USA。SELECT employee_id, last_name, CASE department_id WHEN ( SELECT department_id FROM departments WHERE location_id = 1800) THEN 'Canada' ELSE 'USA' END "location" FROM employees;
 
-  
-  子查询中的空值问题 SELECT last_name, job_id FROM employees WHERE job_id = ( # 子查询为NULL SELECT job_id FROM employees WHERE last_name = 'Haas' );
-  非法使用子查询语句 # 错误代码:1242 # Subquery returns more than 1 row SELECT employee_id, last_name FROM employees WHERE salary = ( SELECT MIN(salary) FROM employees GROUP BY department_id );
9.3:多行子查询
-  多行比较操作符 操作符 含义 IN等于列表中的任意一个 ANY需要和单行比较操作符一起使用,和子查询返回的某一个值比较 ALL需要和单行比较操作符一起使用,和子查询返回的所有值比较 SOME实际上是 ANY的别名,作用相同,一般常使用ANY
-  实例代码 -  返回其他 job_id中比job_id为IT_PROG部门任一工资低的员工的员工号、姓名、job_id以及salary。SELECT employee_id, last_name, job_id, salary FROM employees WHERE job_id <> 'IT_PROG' AND salary < ANY ( SELECT salary FROM employees WHERE job_id = 'IT_PROG' );
-  返回其他 job_id中比job_id为IT_PROG部门所有工资都低的员工的员工、姓名、job_id以及salary。SELECT employee_id, last_name, job_id, salary FROM employees WHERE job_id <> 'IT_PROG' AND salary < ALL ( SELECT salary FROM employees WHERE job_id = 'IT_PROG' );
-  查询平均工资最低的部门 id。# 方式一 SELECT department_id FROM employees GROUP BY department_id HAVING AVG(salary) = ( SELECT MIN(avg_sal) FROM ( SELECT AVG(salary) avg_sal FROM employees GROUP BY department_id ) t_dept_avg_sal ); # 方式二 SELECT department_id FROM employees GROUP BY department_id HAVING AVG(salary) <= ALL( SELECT AVG(salary) avg_sal FROM employees GROUP BY department_id );
 
-  
-  空值问题 -  一行数据都没有 SELECT last_name FROM employees WHERE employee_id NOT IN( SELECT manager_id FROM employees );
 
-  
9.4:相关子查询
-  相关子查询执行流程  如果子查询的执行依赖于外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询就称之为关联子查询。  相关子查询按照一行接一行的顺序执行,主查询的每一行都执行一次子查询。 
  
-  代码示例 -  查询员工中工资大于本部门平均工资的员工的 last_name、salary和其department_id。# 方式一: 相关子查询 SELECT last_name, salary, department_id FROM employees e1 WHERE salary > ( SELECT AVG(salary) FROM employees e2 WHERE department_id = e1.`department_id` ); # 方式二: 在FROM中使用子查询 SELECT e.last_name, e.salary, e.department_id FROM employees e, ( SELECT department_id, AVG(salary) avg_sal FROM employees GROUP BY department_id) t_dept_avg_sal WHERE e.`department_id` = t_dept_avg_sal.department_id AND e.salary > t_dept_avg_sal.avg_sal;
-  查询员工的 id、salary,按照department_name排序。# 在ORDER BY中使用子查询 SELECT employee_id, salary FROM employees e ORDER BY ( SELECT department_name FROM departments d WHERE e.`department_id` = d.`department_id` ) ASC;
 
-  
-  EXISTS与NOT EXISTS关键字关联子查询通常也会和 EXISTS操作符一起来使用,用来检查在子查询中是否存在满足条件的行。- 如果在子查询中不存在满足条件的行:条件返回FALSE、继续在子查询中查找
- 如果在子查询中满足条件的行:不在子查询中继续查找、条件返回TRUE
- NOT EXISTS关键字表示如果不存在某种条件,则返回- TRUE,否则返回- FALSE。
 查询公司管理者的 employee_id、last_name、job_id、department_id信息。#方式1:自连接 SELECT DISTINCT mgr.employee_id, mgr.last_name, mgr.job_id, mgr.department_id FROM employees emp JOIN employees mgr ON emp.manager_id = mgr.`employee_id`; #方式2:子查询 SELECT employee_id, last_name, job_id, department_id FROM employees WHERE employee_id IN ( SELECT DISTINCT manager_id FROM employees ); #方式3:使用EXISTS SELECT employee_id, last_name, job_id, department_id FROM employees e1 WHERE EXISTS ( SELECT * FROM employees e2 WHERE e1.`employee_id` = e2.`manager_id` );查询 departments表中,不存在于employees表中的部门的department_id和department_name。#方式1: SELECT d.department_id, d.department_name FROM employees e RIGHT JOIN departments d ON e.`department_id` = d.`department_id` WHERE e.`department_id` IS NULL; #方式2: SELECT department_id, department_name FROM departments d WHERE NOT EXISTS ( SELECT * FROM employees e WHERE d.`department_id` = e.`department_id` );
- 如果在子查询中不存在满足条件的行:条件返回
-  一个思考题 -  自连接和子查询两种方式有好坏之分吗?  自连接方式好。  题目中可以使用子查询,也可以使用自连接。一般情况建议你使用自连接,因为在许多 BDMS的处理过程中,对于自连接的处理速度要比子查询快得多。 可以这样理解:子查询实际上是通过未知表进行查询后的条件判断,而自连接是通过已知的自身数据表进行条件判断,因此在大部分 DBMS中都对自连接处理进行了优化。
 
-  















