📜  解决查询的子查询

📅  最后修改于: 2020-12-29 04:22:23             🧑  作者: Mango


子查询最好定义为查询中的查询。子查询使您可以编写查询,以选择在查询在运行时实际开发的条件的数据行。更正式地说,它是在另一个SELECT语句的子句之一中使用SELECT语句。实际上,子查询可以包含在另一个子查询中,该子查询也可以在另一个子查询中,依此类推。子查询也可以嵌套在INSERT,UPDATE和DELETE语句中。子查询必须放在括号内。

子查询可在允许表达式的任何地方使用,只要它返回单个值即可。这意味着返回单个值的子查询也可以在FROM子句列表中作为对象列出。之所以称为内联视图,是因为当子查询用作FROM子句的一部分时,它被视为虚拟表或视图。子查询可以放在主查询的FROM子句,WHERE子句或HAVING子句中。

Oracle在WHERE子句中最多允许嵌套255个子查询级别。 FROM子句中表示的嵌套子查询没有任何限制,实际上255个级别的限制实际上根本不是一个限制,因为很少会遇到嵌套超过三或四个级别的子查询。

子查询SELECT语句与用于开始常规查询或外部查询的SELECT语句非常相似。子查询的完整语法为:

( SELECT [DISTINCT] subquery_select_parameter
  FROM {table_name | view_name}
               {table_name | view_name} ...
  [WHERE search_conditions]
  [GROUP BY column_name [,column_name ] ...]
  [HAVING search_conditions] )

子查询的类型

单行子查询:返回单行输出的子查询。它们标志着单行比较运算符的使用,在条件下使用时。

多行子查询:返回多行输出的子查询。他们利用多行运算符如IN,ANY,ALL。可能有子查询也返回多列。

关联子查询:关联子查询取决于外部查询提供的数据。这种类型的子查询还包括使用EXISTS运算符测试满足指定条件的数据行的子查询。

单行子查询

当外部查询的结果基于单个未知值时,将使用单行子查询。尽管此查询类型正式称为“单行”,但该名称暗示该查询返回多列,但仅返回一行结果。但是,单行子查询只能向外部查询返回仅由一列组成的一行结果。

在下面的SELECT查询中,内部SQL仅返回一行,即公司的最低工资。依次使用该值比较所有员工的薪水,并仅显示薪水等于最低薪水的员工。

SELECT first_name, salary, department_id
FROM employees
WHERE salary = (SELECT MIN (salary) 
        FROM employees); 

当需要基于某些条件限制查询的分组结果时,将使用HAVING子句。如果必须将子查询的结果与组函数进行比较,则必须将内部查询嵌套在外部查询的HAVING子句中。

SELECT department_id, MIN (salary)
FROM employees
GROUP BY department_id
HAVING MIN (salary)  < (SELECT AVG (salary)
            FROM employees)

多行子查询

多行子查询是嵌套查询,可以向父查询返回多行结果。多行子查询最常用于WHERE和HAVING子句中。因为它返回多行,则必须通过集运算符(IN,ALL,ANY)。虽然在运算符握住如前面章节中讨论的相同的含义来处理,ANY运算符规定值进行比较,以由子查询而返回的每个值ALL将值与子查询返回的每个值进行比较。

下面的查询显示单行子查询返回多行时的错误。

SELECT    first_name, department_id
FROM employees
WHERE department_id = (SELECT department_id
            FROM employees
            WHERE LOCATION_ID = 100)
department_id = (select
               *
ERROR at line 4:
ORA-01427: single-row subquery returns more than one row 

多行运算符的用法

  • [> ALL]大于子查询返回的最大值

  • [

  • [

  • [> ANY]大于子查询返回的最小值

  • [= ANY]等于子查询返回的任何值(与IN相同)

上面的SQL可以使用如下的IN运算符进行重写。

SELECT    first_name, department_id
FROM employees
WHERE department_id IN (SELECT department_id
                           FROM departments
                           WHERE LOCATION_ID = 100)

注意,在上面的查询中,IN匹配从子查询返回的部门ID,将其与主查询中的部门ID进行比较,并返回满足条件的员工姓名。

对于上述查询,联接将是更好的解决方案,但出于说明的目的,已在其中使用了子查询。

关联子查询

与常规子查询(外部查询依赖于内部查询提供的值)相反,相关子查询是内部查询依赖于外部查询提供的值的子查询。这意味着在相关的子查询中,内部查询将重复执行,对于外部查询可能选择的每一行,都会重复执行一次。

相关子查询可以生成结果表,以回答复杂的管理问题。

考虑下面的SELECT查询。与先前考虑的子查询不同,此SELECT语句中的子查询无法独立于主查询进行解析。注意,外部查询指定从雇员表中选择别名为e1的行。内部查询将别名为e2的雇员表的雇员部门编号列(DepartmentNumber)与别名表名称为e1的同一列进行比较。

SELECT EMPLOYEE_ID, salary, department_id
FROM   employees E
WHERE salary > (SELECT AVG(salary)
                FROM   EMP T
                WHERE E.department_id = T.department_id)

多列子查询

多列子查询将多个列返回到外部查询,并且可以在外部查询的FROM,WHERE或HAVING子句中列出。例如,以下查询显示当前薪水在1000到2000之间并且在部门10或20工作的员工的历史记录。

SELECT first_name, job_id, salary
FROM emp_history
WHERE (salary, department_id) in (SELECT salary, department_id
                  FROM employees
                   WHERE salary BETWEEN 1000 and 2000 
                  AND department_id BETWEEN 10 and 20)
ORDER BY first_name;

在外部查询的FROM子句中使用多列子查询时,它将创建一个临时表,该表可以由外部查询的其他子句引用。此临时表更正式地称为内联视图。子查询的结果与FROM子句中的任何其他表一样对待。如果临时表包含分组的数据,则将分组的子集视为表中数据的单独行。考虑以下查询中的FROM子句。子查询形成的内联视图是主查询的数据源。

SELECT * 
FROM (SELECT salary, department_id
    FROM employees
     WHERE salary BETWEEN 1000 and 2000);