【Oracle】 Oracle之SQL的子查询

前情提要:本篇博客将详细介绍oracle中SQL的子查询,包括子查询相关的语法,使用规则,还有子查询的常见类型(单行子查询、多行子查询、多列子查询、内联视图),并且有详细的使用示例和解析

oracle版本:19c

一、子查询相关介绍

1.1 子查询的语法

  • 子查询(内部查询)在主查询(外部查询)之前执行。

  • 子查询的结果由主查询使用。

sql 复制代码
SELECT	select_list
FROM	table
WHERE	expr operator
		 	(SELECT	select_list
		       FROM		table);

1.2 使用子查询的规则和准则

  • 将子查询括在括号中(括号中的子查询语句不需要写分号)。

  • 虽然子查询可以出现在比较条件的任意一侧,但是一般将子查询放在比较条件的右侧,以提高可读性。

  • 将单行运算符用于单行子查询,将多行运算符用于多行子查询。

二、使用子查询解决查询问题

问题:谁在Davies之后入职?

sql 复制代码
-- 单独查询Davies的入职日期
-- 先修改时间格式方便查看
SQL> ALTER SESSION SET nls_date_format = 'yyyy-mm-dd';
Session altered.

SQL> SELECT hire_date FROM employees WHERE last_name = 'Davies';

HIRE_DATE
----------
2005-01-29
-- 可见Davies的入职日期是2005-01-29,所以在Davies之后雇佣的员工的入职时间要比Davies的入职时间大(越接近现在的时间越大)

SQL> SELECT LAST_NAME , HIRE_DATE
  2  FROM EMPLOYEES
  3  WHERE HIRE_DATE > (SELECT HIRE_DATE FROM EMPLOYEES WHERE LAST_NAME='Davies');
  
LAST_NAME                 HIRE_DATE
------------------------- ----------
Feeney                    2006-05-23
OConnell                  2007-06-21
Grant                     2008-01-13
Fay                       2005-08-17

81 rows selected.

2.1 在子查询中使用聚合函数

使用示例

  • 找到工资最低的人的信息
sql 复制代码
SQL> SELECT last_name, job_id, salary
  2  FROM   employees
  3  WHERE  salary = (SELECT MIN(salary) FROM employees); -- 子查询返回employees表中的最低工资

LAST_NAME                 JOB_ID         SALARY
------------------------- ---------- ----------
Olson                     ST_CLERK         2100

2.2 子查询中的HAVING子句

  • Oracle服务器首先执行子查询。

  • Oracle服务器将结果返回到主查询的HAVING子句中。

使用示例

  • 找到哪些部门的最低工资是大于30号部门最低工资,并输出相关信息
sql 复制代码
SQL> SELECT   department_id, MIN(salary)
  2  FROM     employees
  3  GROUP BY department_id
  4  HAVING   MIN(salary) >(SELECT MIN(salary) FROM employees WHERE  department_id = 30); -- 子查询找到了30号部门的最低工资

DEPARTMENT_ID MIN(SALARY)
------------- -----------
           40        6500
          110        8300
           90       17000
           70       10000
                     7000
           10        4400
           20        6000
           60        4200
          100        6900
           80        6100

10 rows selected.

三、子查询的类型

3.1 单行子查询

特点:

  • 只返回一行

  • 使用单行比较运算符(单行子查询返回单行单列的结果,使用单行比较运算符进行条件判断)

适用场景:

  • 查找比某个特定值(由子查询提供)更大的数据

  • 获取精确匹配的值

单行子查询执行示例

  • 找到和Austin一样的工作的人,并且这个(这些)人工资大于Austin
sql 复制代码
SQL> SELECT last_name, job_id, salary
  2  FROM   employees
  3  WHERE  job_id =  (SELECT job_id
  4                   FROM   employees
  5                   WHERE  last_name = 'Austin')		-- 子查询查出Austin的工作ID
  6  AND    salary >  (SELECT salary
  7                   FROM   employees
  8                   WHERE  last_name = 'Austin');		-- 子查询查出Austin的工资

LAST_NAME                 JOB_ID         SALARY
------------------------- ---------- ----------
Hunold                    IT_PROG          9000
Ernst                     IT_PROG          6000	

-- 单独执行子查询确认结果是否准确
SQL> SELECT job_id FROM employees WHERE last_name = 'Austin';

JOB_ID
----------
IT_PROG

SQL> SELECT salary FROM employees WHERE last_name = 'Austin';

    SALARY
----------
      4800

3.2 多行子查询

特点:

  • 返回多行

  • 使用多行比较运算符

适用场景:

  • IN:匹配子查询返回列表中的任意一个值

  • ANY :满足子查询结果集中任意一行的条件

  • ALL :满足子查询结果集中所有行的条件

使用示例:

  • 在多行子查询中使用ANY运算符
sql 复制代码
-- 找到工资小于从事IT_PROG岗位的人的工资,并且不能包括IT_PROG人员。
SQL> SELECT employee_id, last_name, job_id, salary
  2  FROM   employees
  3  WHERE  salary < ANY (SELECT salary FROM  employees WHERE  job_id = 'IT_PROG')	-- 子查询返回IT_PROG工作的所有工资
  4  AND    job_id <> 'IT_PROG';
  
EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        122 Kaufling                  ST_MAN           7900
        153 Olsen                     SA_REP           8000
        159 Smith                     SA_REP           8000
        120 Weiss                     ST_MAN           8000
        121 Fripp                     ST_MAN           8200
        110 Chen                      FI_ACCOUNT       8200
        206 Gietz                     AC_ACCOUNT       8300
        177 Livingston                SA_REP           8400
        176 Taylor                    SA_REP           8600
        175 Hutton                    SA_REP           8800

76 rows selected.

-- 单独查看子查询的结果
SQL> SELECT salary FROM  employees WHERE  job_id = 'IT_PROG';

    SALARY
----------
      9000
      6000
      4800
      4800
      4200
      
-- 所以上述示例可以理解为找出只要工作不是IT_PROG并且工资小于9000的所有人的信息
  • 在多行子查询中使用ALL运算符
sql 复制代码
SQL> SELECT employee_id, last_name, job_id, salary
  2  FROM   employees
  3  WHERE  salary < ALL(SELECT salary FROM  employees WHERE  job_id = 'IT_PROG')
  4  AND    job_id <> 'IT_PROG';

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        140 Patel                     ST_CLERK         2500
        131 Marlow                    ST_CLERK         2500
        119 Colmenares                PU_CLERK         2500
        191 Perkins                   SH_CLERK         2500
        182 Sullivan                  SH_CLERK         2500
        144 Vargas                    ST_CLERK         2500
        127 Landry                    ST_CLERK         2400
        135 Gee                       ST_CLERK         2400
        128 Markle                    ST_CLERK         2200
        136 Philtanker                ST_CLERK         2200
        132 Olson                     ST_CLERK         2100

44 rows selected.

-- 该例可以理解为找出只要工作不是IT_PROG并且工资小于IT_PROG岗的最低工资的所有人的信息

3.3 多列子查询

特点:

  • 多列子查询将多个列返回到外部查询。

  • 多列比较中的列比较可以成对或非成对。

  • 也可以在SELECT语句的FROM子句中使用多列子查询。

  • 可以是单行多列或多行多列

适用场景:

  • 需要同时匹配多个条件的复杂查询

  • 比较多个列的值

使用示例

  • 显示每个部门中薪水最低的员工
sql 复制代码
SQL> SELECT first_name, department_id, salary
  2  FROM employees
  3  WHERE (salary, department_id) IN (SELECT MIN(salary), department_id FROM employees GROUP BY department_id)
  4  ORDER BY department_id;
FIRST_NAME           DEPARTMENT_ID     SALARY
-------------------- ------------- ----------
Jennifer                        10       4400
Pat                             20       6000
Karen                           30       2500
Susan                           40       6500
TJ                              50       2100
Diana                           60       4200
Hermann                         70      10000
Sundita                         80       6100
Neena                           90      17000
Lex                             90      17000
Luis                           100       6900

FIRST_NAME           DEPARTMENT_ID     SALARY
-------------------- ------------- ----------
William                        110       8300

12 rows selected.

-- 子查询返回的是多行多列数据,在该例中进行多列匹配,当工资和部门ID同时匹配子查询的结果时条件成立。
-- 单独查看子查询结果
SQL> SELECT MIN(salary), department_id FROM employees GROUP BY department_id;

MIN(SALARY) DEPARTMENT_ID
----------- -------------
       2100            50
       6500            40
       8300           110
      17000            90
       2500            30
      10000            70
       7000
       4400            10
       6000            20
       4200            60
       6900           100

MIN(SALARY) DEPARTMENT_ID
----------- -------------
       6100            80

12 rows selected.

3.4 内联视图

特点:

  • 在FROM子句中使用的子查询,作为派生表提供临时结果集

  • 必须为内联视图指定别名

  • 外层查询引用其列时需采用"别名.列名"格式

  • 可以包含ORDER BY子句(与普通子查询不同)

适用场景

  • 将聚合结果作为虚拟表进行关联

  • 创建临时结果集供主查询使用

  • 实现复杂的数据转换和计算

使用示例:

sql 复制代码
-- 查看所有员工总工资
SQL> SELECT SUMS FROM (SELECT SUM(SALARY) AS SUMS  FROM EMPLOYEES);

      SUMS
----------
    691416
    
-- 虽然该例等价于SELECT SUM(SALARY) AS SUMS FROM EMPLOYEES,但是此处主要为了体现内联视图的作用才这么写。

四、子查询错误使用示例

示例

  • 使用单行运算符匹配多行子查询返回的结果
sql 复制代码
SQL> SELECT employee_id, last_name
  2  FROM   employees
  3  WHERE  salary = (SELECT   MIN(salary) FROM employees GROUP BY department_id);

WHERE  salary = (SELECT   MIN(salary) FROM employees GROUP BY department_id)
                 *
ERROR at line 3:
ORA-01427: single-row subquery returns more than one row

-- 错误原因:使用单行运算符匹配多行子查询返回的结果
-- 单独查看子查询
SQL> SELECT   MIN(salary) FROM employees GROUP BY department_id;	-- 查找每个部门的最低工资

MIN(SALARY)
-----------
       2100
       6500
       8300
      17000
       2500
      10000
       7000
       4400
       6000
       4200
       6900

MIN(SALARY)
-----------
       6100

12 rows selected.
  • 子查询不返回任何行
sql 复制代码
SQL> SELECT last_name, job_id
  2  FROM   employees
  3  WHERE  job_id = (SELECT job_id FROM   employees WHERE  last_name = 'Haas');
no rows selected

-- 这个语句本身没有语法错误,但是员工表中没有Haas这个人的信息,所以子查询返回的是空值
-- 查看子查询
SQL> SELECT job_id FROM   employees WHERE  last_name = 'Haas';
no rows selected
相关推荐
m0_596406371 小时前
CSS复杂组件如何拆解_使用Sass将组件逻辑细化为小文件
jvm·数据库·python
遇印记2 小时前
网络运维DDos攻击
运维·网络·ddos
司南-70492 小时前
opencode环境搭 并 配置自定义BASE URL
linux·运维·服务器·人工智能
数智化管理手记2 小时前
异常反复出现?精益生产生产异常闭环的三大常见问题场景
大数据·数据库·低代码·制造·精益工程
无巧不成书02182 小时前
Rust开发环境完全指南:Windows/Linux双平台配置与实战
linux·windows·rust·gnu·msvc·mingw-w64安装·镜像配置
2301_816660212 小时前
golang如何实现SSRF防护策略_golang SSRF防护策略实现方案
jvm·数据库·python
流年如夢2 小时前
自定义类型进阶:联合与枚举
java·c语言·开发语言·数据结构·数据库·c++·算法
解救女汉子2 小时前
CSS3 按钮悬停时显示手型光标(cursor- pointer)的正确写法
jvm·数据库·python