#进阶7:子查询
/*
含义:
出现在其他语句中的SELECT语句,称为子查询或内查询
外部的查询语句,称为主查询或外查询
分类:
按子查询出现的位置:
SELECT后面:仅仅支持支标量子查询
FROM后面:支持表子查询
WHERE或HAVING后面★:标量子查询(单行);列子查询(多行);行子查询
exists后面(相关子查询):表子查询
按结果集的行列不同:
标量子查询(结果集只有一行一列)
列子查询(结果集只有一列多行)
行子查询(结果含有多行多列)
表子查询(结果集一般为多行多列
*/
#一、WHERE或HAVING后面
#1.标量子查询(单行子查询)
#2.列子查询(多行子查询)
#3.行子查询(多列多行)
/*
特点:1.子查询放在小括号内
2.子查询一般放在条件的右侧
3.标量子查询,一般搭配单行操作符使用
> < >= <= = <>
列子查询:一般搭配着多行操作符使用 IN、ANY/SOME、ALL
4.子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果
*/
#1.标量子查询
#案例1:谁的工资比 Abel高
SELECT
*
FROM
employees
WHERE
salary > ( SELECT salary FROM employees WHERE last_name = 'Abel' );
#案例2:返回JOB_ID与141号员工相同,salary比143号员工多的员工 姓名,JOB_I和工资
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 );
#案例3:返回公司工资最少的员工的LAST_ANME,JOB_ID和SALARY
SELECT
last_name,
job_id,
salary
FROM
employees
WHERE
salary = ( SELECT MIN( salary ) FROM employees );
#案例4:查询最低工资大于50号部门最低工资的部门ID和其最低工资
SELECT
department_id,
MIN( salary )
FROM
employees
GROUP BY department_id
HAVING
MIN( salary ) > ( SELECT MIN( salary ) FROM employees WHERE department_id = 50 );
#非法使用标量子查询
#2.列子查询(多行子查询)
/*
IN/NOT IN:等于列表中的任意一个
ANY/SOME:和子查询返回某一个值比较
ALL:和子查询返回的所有值比较
*/
#案例1:返回location_id是1400或1700的部门中的所有员工姓名
#方法1:
SELECT
last_name,
location_id
FROM
employees E
INNER JOIN departments D ON E.department_id = D.department_id
WHERE
location_id IN ( 1400, 1700 );
#方法2
SELECT
last_name
FROM
employees
WHERE
department_id IN ( SELECT DISTINCT department_id FROM departments WHERE location_id IN ( 1400, 1700 ) );
#案例2:返回其他部门中比JOB_ID为'IT_PROG'部门任一工资低的员工的工号、姓名、JOB_ID以及SALARY
SELECT
employee_id,
last_name,
job_id,
salary
FROM
employees
WHERE
salary< ANY ( SELECT DISTINCT salary FROM employees WHERE job_id = 'IT_PROG' )AND job_id <> 'IT_PROG';
#3.案例3:返回其他部门中比JOB_ID为'IT_PROG'部门所有工资都低的员工的员工号,姓名,job_id以及salary
SELECT
employee_id,
last_name,
job_id,
salary
FROM
employees
WHERE
salary < ALL ( SELECT salary FROM employees WHERE job_id = 'IT_PROG' )
AND job_id <> 'IT_PROG';
#3.行子查询(结果集一行多列或多行多列)
#案例:查询员工编号最小并且工资最高的员工信息
#方法1:
SELECT
*
FROM
employees
WHERE
employee_id = ( SELECT MIN( employee_id ) FROM employees )
AND salary = ( SELECT MAX( salary ) FROM employees );
#方法2:
SELECT
*
FROM
employees
WHERE
( employee_id, salary ) = ( SELECT MIN( employee_id ), MAX( salary ) FROM employees );
#二、SELECT后面的子查询(仅仅支持标量子查询)
#案例1:查询每个部门的员工个数
SELECT
D.*,
(SELECT COUNT( employee_id ) FROM employees E WHERE E.department_id=D.department_id)
FROM
departments D;
#案例2:查询员工号=102的部门名
SELECT
( SELECT department_name FROM departments D INNER JOIN employees E ON D.department_id = E.department_id WHERE employee_id = 102 ) 部门名;
#三:from后面
/*
注意:将子查询结果充当一张表,要求必须取别名
*/
#案例:查询每个部门的平均工资的工资等级
SELECT
AG_DEP.*,
GRADE_LEVEL
FROM
( SELECT AVG( salary ) AG, department_id FROM employees GROUP BY department_id ) AG_DEP
INNER JOIN job_grades J ON AG_DEP.AG BETWEEN J.LOWEST_SAL
AND J.HIGHEST_SAL;
#四、EXISTS后面(相关子查询)
/*
语法:
EXISTS (完整的查询语句)
结果:1或0
*/
SELECT EXISTS(SELECT employee_id FROM employees WHERE salary = 30000);
#案例1:查询有员工的部门名
SELECT
department_name
FROM
departments D
WHERE
EXISTS ( SELECT * FROM employees E WHERE E.department_id = D.department_id );
#方法2:
SELECT
department_name
FROM
departments D
WHERE
D.department_id IN ( SELECT department_id FROM employees )
测试题:
#1.查询和ZLOTKEY相同部门的员工姓名和工资
SELECT
last_name,
salary,
FROM
employees
WHERE
department_id = ( SELECT department_id FROM employees WHERE last_name = 'ZLOTKEY' );
#2.查询工资比公司平均工资高的员工的员工号,姓名和工资
SELECT
employee_id,
last_name,
salary
FROM
employees
WHERE
salary > ( SELECT AVG( salary ) FROM employees );
#3.查询各个部门中工资比本部门平均工资高的员工的员工号,姓名和工资
SELECT
employee_id,
last_name,
salary
FROM
employees
WHERE
salary > ( SELECT AVG( salary ) FROM employees )
GROUP BY
department_id;
#4.查询和姓名中包含字母u的员工在相同部门的员工的员工号和姓名
SELECT
employee_id,
last_name
FROM
employees
WHERE
department_id IN ( SELECT department_id FROM employees WHERE last_name LIKE '%U%' );
#5.查询在部门的location_id为1700的部门工作的员工的员工号
SELECT
employee_id
FROM
employees
WHERE
department_id IN ( SELECT department_id FROM departments WHERE location_id = 1700 );
#6.查询管理者是King的员工姓名和工资
SELECT
last_name,
salary
FROM
employees
WHERE
manager_id IN ( SELECT employee_id FROM employees WHERE last_name = 'K_ING' );
#7.查询工资最高的员工的姓名,要求FIRST_NAME和LAST_NAME显示为一列,列名为姓.名
SELECT
CONCAT( first_name, '.', last_name ) AS '姓.名'
FROM
employees
WHERE
salary = ( SELECT MAX( salary ) FROM employees );