• 子查询


    含义:出现在其它语句中的select语句,称为子查询或内查询

    外部的语句可以是 insert、update、delete、select
    select在外部的查询语句,称为主查询或外查询

    分类:
    按子查询出现的位置:
    SELECT后:仅仅支持标量子查询

    FROM后:支持表子查询

    WHERE或HAVING后:

      常用于 标量子查询√
      列子查询√

      少用于 行子查询

    EXISTS后(可以叫相关子查询):所有子查询都行

    按结果集的行列数不同:

    标量 子查询/单行子查询 结果集 一行一列或者称为
    列 子查询/多行子查询 结果集 一列多行
    行 子查询 结果集 多行多列
    表 子查询 一般为多行多列

    #WHERE或HAVING后

    1 标量子查询 单行子查询(一行一列)

    2 列子查询 多行子查询 (一行多列)

    3 行子查询 (多列多行)

    单行和多行的特点:
    1 子查询放在小括号内
    2 子查询一般放在条件的右侧
    3 标量子查询,一般搭配着单行操作符使用
    > < >= <= <>

    列子查询的特点,一般搭配着多行操作符使用
    in、any/some、all

    子查询的执行顺序优先于主查询,因为查询的条件用到子查询的结果

    #1 标量子查询 单行子查询

    #案例:谁的工资比abel高?
    #第1步 查询Abel的工资

    SELECT salary
    FROM employees
    WHERE last_name='Abel'

    #第2步 查询员工的信息满足salary>1结果的结果

    SELECT *
    FROM employees
    WHERE salary>(
    SELECT salary
    FROM employees
    WHERE last_name='Abel'
    );#把第1步称为单行子查询,或标量子查询

    #案例:返回job_id与141号员工相同,salary比143号员工多的员工 员工姓名 job_id和工资
    #第1步查询141员工的job id

    SELECT job_id
    FROM employees
    WHERE employee_id=141;

    #第2步查询143员工的salary

    SELECT salary
    FROM employees
    WHERE employee_id=143;
    #第3步查询员工的姓名、job id、工资,要求jobid=1并且salary>2
    SELECT last_name,job_id,salary
    FROM employees
    WHERE job_id=(
    SELECT job_id
    FROM employees
    WHERE employee_id=141
    )
    AND(
    SELECT salary
    FROM employees
    WHERE employee_id=143
    )

    #在子查询中使用分组函数

    #案例:返回公司工资最少的员工的last_name、job_id、salary
    #第1步查询公司的 最低工资

    SELECT MIN(salary)
    FROM employees;

    #第2步查询last_name、job_id、salary,要求salary=1

    SELECT last_name,job_id,salary
    FROM employees
    WHERE salary=(
    SELECT MIN(salary)
    FROM employees
    );

    #子查询中的having子句

    #案例:查询最低工资大于50部门的最低工资,的部门id和最低工资
    #第1步查询50部门的最低工资

    SELECT MIN(salary)
    FROM employees
    WHERE department_id=50;

    #第2步查询每个部门的最低工资

    SELECT MIN(salary),department_id
    FROM employees
    GROUP BY department_id;

    #第3步 在2基础上筛选,满足MIN(salary)》1的部门和最低工资

    SELECT MIN(salary),department_id
    FROM employees
    GROUP BY department_id
    HAVING MIN(salary)>(
    SELECT MIN(salary)
    FROM employees
    WHERE department_id=50
    );

    #非法使用标量子查询

    SELECT MIN(salary),department_id
    FROM employees
    GROUP BY department_id
    HAVING MIN(salary)>(
    SELECT salary
    FROM employees
    WHERE department_id=50
    );
    
    /*
    单行操作符(操作单个值的)只能搭配,单行子查询(标量子查询)
    */
    SELECT MIN(salary),department_id
    FROM employees
    GROUP BY department_id
    HAVING MIN(salary)>(
    SELECT salary
    FROM employees
    WHERE department_id=250
    );
    /*
    子查询的结果不是一行一列
    *

    不管是什么样的子查询都放在小括号中

    #2多行子查询(列子查询)(一列多行)

    特点:返回多行

    使用:需要搭配多行操作符来使用

    把模糊查询小括号里放的常量,替换成了查询语句,查询语句的结果代替了模糊查询用的常量(查询语句的结果是一个列表)

    常见的: 
    操作符 含义
    IN/NOT IN 等于类表中的任意一个
    ANY|SOME 和子查询返回的 某一个值比较
    ALL 和子查询返回的 所有值比较

    IN意义:等于类表中的任意一个
    NOT IN意义:这里面的都不是

    ANY|SOME意义:满足一个即可。例如a<ANY(10,20,30) a=15,这样就可以被查询出来。
    使用的较少因为可以被代替:a>MIN()就行了,省去了麻烦事

    ALL意义:满足所有的。例如a<ANY(10,20,30) a=15,这样就不能被查询出来。
    也可以被代替,a>MAX()

    #案例:返回 location_id是1400或1700的部门中的 所有员工姓名

    #1.查询location_id是1400或1700的部门编号

    SELECT DISTINCT department_id #防止重复提高效率
    FROM departments
    WHERE location_id=1400 OR location_id=1700 
    //WHERE location_id=1400 || location_id=1700 
    //WHERE location_id IN(1400,1700);

    #2.查询员工姓名,要求部门号是1列表中的 某一个

    SELECT last_name
    FROM employees
    WHERE department_id IN(
    SELECT DISTINCT department_id #防止重复提高效率
    FROM departments
    WHERE location_id IN(1400,1700)
    );

    #还可以

    SELECT last_name
    FROM employees
    WHERE department_id=ANY(#等于里面任意一个
    SELECT DISTINCT department_id #防止重复提高效率
    FROM departments
    WHERE location_id IN(1400,1700)
    );
    SELECT last_name
    FROM employees
    WHERE department_id NOT IN(
    SELECT DISTINCT department_id #防止重复提高效率
    FROM departments
    WHERE location_id IN(1400,1700)
    );
    SELECT last_name
    FROM employees
    WHERE department_id !=ALL(#相当于并且
    SELECT DISTINCT department_id #防止重复提高效率
    FROM departments
    WHERE location_id IN(1400,1700)
    );
    SELECT last_name
    FROM employees
    WHERE department_id !=ANY(#相当于或者
    SELECT DISTINCT department_id #防止重复提高效率
    FROM departments
    WHERE location_id IN(1400,1700)
    );

    #案例:返回其他部门中比job_id为 it_prog 部门仁义工资低的员工的:工号姓名、job_id、salary

    #1.查询job_id为 it_prog 任意一个工资

    SELECT DISTINCT salary
    FROM employees
    WHERE job_id='IT_PROG';

    #2.查询员工号、姓名、job_id、salary salary<1任意一个

    SELECT last_name,employee_id,job_id,salary 
    FROM employees
    WHERE salary<ANY(
    SELECT DISTINCT salary
    FROM employees
    WHERE job_id='IT_PROG'
    )
    AND job_id != 'IT_PROG';

    #或,只要不超过最大的就可以满足

    SELECT last_name,employee_id,job_id,salary 
    FROM employees
    WHERE salary<(
    SELECT DISTINCT MAX(salary)
    FROM employees
    WHERE job_id='IT_PROG'
    )
    AND job_id != 'IT_PROG';

    #案例:返回其他部门中比job_id为 it_prog 部门所有工资低的员工的:工号姓名、job_id、salary

    SELECT last_name,employee_id,job_id,salary 
    FROM employees
    WHERE salary<ALL(
    SELECT DISTINCT salary
    FROM employees
    WHERE job_id='IT_PROG'
    )
    AND job_id != 'IT_PROG';

    #或,只要不低于最小的就可以满足

    SELECT last_name,employee_id,job_id,salary 
    FROM employees
    WHERE salary<(
    SELECT DISTINCT MIN(salary)
    FROM employees
    WHERE job_id='IT_PROG'
    )
    AND job_id != 'IT_PROG';

    #3.行子查询(结果集一行多列,多行多列)

    #案例:查询出员工编号最小 并且 工资最高的员工信息

    #1:查询最小的员工编号

    SELECT MIN(employee_id)
    FROM employees;

    #2:查询最低工资

    SELECT MAX(salary)
    FROM employees;


    #3:查询员工信息

    SELECT *
    FROM employees
    WHERE employee_id=(
    SELECT MIN(employee_id)
    FROM employees
    )
    AND salary=(
    SELECT MAX(salary)
    FROM employees
    );

    #用行子查询代替

    SELECT *
    FROM employees
    WHERE (employee_id,salary)=(
    SELECT MIN(employee_id),MAX(salary)
    FROM employees
    );
    /*
    用的不多,因为有局限性
    要求连接条件的操作符必须一样
    */

    二、SELECT后

    #案例:查询每个部门的员工个数

    SELECT d.*,(
    SELECT COUNT(*)
    FROM employees e
    WHERE e.department_id=d.department_id
    ) AS 个数
    FROM departments d;

    #案例:查询员工工号=102的部门名

    SELECT ( 
    SELECT department_name
    FROM departments d
    INNER JOIN employees e
    ON d.department_id =e.department_id
    WHERE e.employee_id=102
    ) 部门名;
    /*
    仅仅支持标量子查询
    */

    三、from后面:

    放在from后面一般的就是表,相当于把子查询的结果集充当一个表格来使用,充当数据源
    要求:必须要起别名,否则找不到
    表子查询

    #案例:查询每个部门的平均工资的工资等级
    #1 查询每个部门的平均工资

    SELECT AVG(salary),department_id
    FROM employees
    GROUP BY department_id;

    #2 连接1的结果集和工资等级表 筛选条件between

    SELECT ag_dep.*,g.grade_level
    FROM (
    SELECT AVG(salary) ag,department_id
    FROM employees
    GROUP BY department_id
    ) AS ag_dep
    INNER JOIN job_grades g
    ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;

    四、EXISTS后(相关子查询)

    1代表true
    2代表false

    语法
    EXISTS(完整的查询语句)
    结果:
    1或0

    SELECT EXISTS(
    SELECT employee_id 
    FROM employees
    WHERE salary =300000    
    );

    #案例:查询有员工名的部门名

    SELECT department_name
    FROM departments d
    WHERE EXISTS(
    SELECT *
    FROM employees e 
    WHERE d.department_id=e.department_id
    );
    /*
    和其他子查询不一样,前面的子查询先执行,因为主查询用到子查询的结果
    而这个先去执行主查询,根据主查询的结果,再去过滤。这就是相关子查询
    子查询涉及到了主查询的字段
    */

    #使用in的方式代替:能用 EXISTS就一定能用in代替

    SELECT department_name
    FROM departments d
    WHERE d.department_id IN(
    SELECT department_id
    FROM employees
    );

    #案例2:查询没有女朋友的男神信息

    UPDATE beauty SET boyfriend_id = NULL WHERE id=10;
    
    #IN 的方式
    SELECT bo.*
    FROM boys bo
    WHERE bo.id NOT IN(
    SELECT boyfriend_id
    FROM beauty b
    WHERE bo.id=b.boyfriend_id
    );
    
    #EXISTS
    SELECT bo.*
    FROM boys bo
    WHERE NOT EXISTS(
    SELECT boyfriend_id
    FROM beauty b
    WHERE bo.id=b.boyfriend_id
    );
  • 相关阅读:
    时间转换成时间戳
    元字符为名称的时候,使用两个反斜杠转义:\
    批量修改文件夹及文件用户权限和用户组权限 centos
    HDU6797 多校第三场 Tokitsukaze and Rescue
    AtCoder Regular Contest 103 E
    2020牛客第六场 B题 Binary Vector
    Codeforces Round #659 (Div. 2) B1. Koa and the Beach (Easy Version)
    Codeforces Round #659 (Div. 2) C. String Transformation 1
    Codeforces Round #659 (Div. 2) D GameGame
    P3194 [HNOI2008]水平可见直线 计算几何栈维护下凸壳
  • 原文地址:https://www.cnblogs.com/rijiyuelei/p/12324600.html
Copyright © 2020-2023  润新知