Oracle DB使用子查询来解决查询(二)

2014-11-24 16:24:35 · 作者: · 浏览: 1
R at line 3:
ORA-01427: single-row subquery returns more than one row
子查询的常见错误是单行子查询返回了多行。
在示例的SQL 语句中,子查询包含一个GROUP BY子句,这意味着该子查询将返回多行,每行都对应于一个它找到的组。这种情况下,子查询的结果为4400、6000、
2500、4200、7000、17000和8300。
外部查询将采用这些结果,并在其WHERE子句中使用它们。该WHERE子句包含一个等于(=) 运算符,该运算符是一个只需要一个值的单行比较运算符。=运算符无法接受子查询中的多个值,因此产生了错误。
要更正此错误,请将=运算符更改为IN。
内部查询没有返回任何行
因为没有名为“Haas”的雇员,所以子查询没有返回任何行。
hr@TEST0924> SELECT last_name, job_id FROM employees
2 WHERE job_id =
3 (SELECT job_id FROM employees WHERE last_name = 'Haas');
no rows selected
子查询的另外常见问题是内部查询没有返回任何行。
在示例的SQL 语句中,子查询包含一个WHERE子句。据推测,该语句的目的是要查找名为Haas 的雇员。该语句正确,但是因为没有名为“Haas”的雇员,所以执行时没有选择任何行。因此,子查询不会返回任何行。
外部查询采用子查询的结果(空值),并在其WHERE子句中使用这些结果。外部查询没有找到职务ID 等于空值的雇员,因此不会返回任何行。即使存在值为空的职务,也不会返回行,因为两个空值的比较会产生一个空值,从而使WHERE条件不为“真”。
多行子查询
返回多个行
使用多行比较运算符
返回多行的子查询被称为多行子查询。应对多行子查询使用多行运算符,而不是使用单行运算符。多行运算符需要一个或多个值:
SELECT last_name, salary, department_id FROM employees
WHERE salary IN
(SELECT MIN(salary) FROM employees GROUP BY department_id);
示例:
查找其薪金等于各个部门最低薪金的雇员。
先执行内部查询,生成一个查询结果。然后可以处理主查询块,使用内部查询返回的值完善其搜索条件。事实上,主查询将以下面的形式出现在Oracle Server 上:
SELECT last_name, salary, department_id FROM employees
WHERE salary IN (2500, 4200, 4400, 6000, 7000, 8300, 8600, 17000);
在多行子查询中使用ANY运算符
SELECT employee_id, last_name, job_id, salary FROM employees
WHERE salary < ANY
(SELECT salary FROM employees WHERE job_id = 'IT_PROG')
AND job_id <> 'IT_PROG';
ANY运算符(及其同义词SOME运算符)用于将某个值与子查询返回的每个值进行比较。
示例显示不是IT 程序员且薪金低于任一IT 程序员的雇员。程序员的最高薪金为$9,000。
>ANY表示高于最低值。
=ANY等同于IN。
在多行子查询中使用ALL运算符
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';
在多行子查询中使用ALL运算符
ALL运算符用于将某个值与子查询返回的每个值进行比较。示例显示薪金低于职务ID 为IT_PROG的任何雇员的薪金且职务不是IT_PROG的雇员。
>ALL表示大于最高值,
NOT运算符可以与IN、ANY和ALL运算符一起使用。
使用EXISTS运算符
SELECT * FROM departments WHERE NOT EXISTS
(SELECT * FROM employees WHERE employees.department_id=departments.department_id);
使用EXISTS运算符
在查询中使用EXISTS运算符,查询结果取决于某些行是否在表中存在。如果子查询至少返回一行,则求值结果为TRUE。
示例显示没有雇员的部门。对于DEPARTMENTS表中每一行,检查条件,看一看在EMPLOYEES表中是否存在具有相同部门ID 的行。如果不存在这样的行,则相应
行满足条件,从而选择该行。如果EMPLOYEES表中存在相应行,则不选择该行。
子查询中的空值
SELECT emp.last_name FROM employees emp WHERE emp.employee_id NOT IN
(SELECT mgr.manager_id FROM employees mgr);
示例中的SQL 语句尝试显示没有任何下属的所有雇员。逻辑上,此SQL 语句应该返回12 行。但是,该SQL 语句没有返回任何行。因为内部查询返回的值中有一个为空值,所以整个查询不会返回任何行。
原因是所有条件与空值进行比较后都会产生一个空值。因此,只要子查询的结果集中可能包含空值,就不要使用NOT IN运算符。NOT IN运算符等同于<> ALL。
请注意,如果使用的是IN运算符,则子查询的结果集中存在空值就不会成为问题。IN运算符等同于=ANY。
例如,要显示具有下属的雇员,可以使用下面的SQL 语句:
SELECT emp.last_name FROM employees emp WHERE emp.employee_id IN
(SELECT mgr.manager_id FROM employees mgr);
另外,可以在子查询中包括WHERE子句,用来显示没有下属的所有雇员:
SELECT last_name FROM employees WHERE employee_id NOT IN
(SELECT manager_id FROM employees WHERE manager_id IS NOT NULL);
小结
子查询是一个SELECT语句,它嵌入到另一个SQL 语句的子句中。当查询基于带有未知中间值的搜索标准时,使用子查询非常有帮助。
子查询具有以下特性:
可以将一行数据传递给包含单行运算符(如=、<>、>、>=、<或<=)的主语句
可以将多行数据传递给包含多行运算符(如IN)的主语句
Oracle Server 先处理子查询,随后WHERE或HAVING子句会使用生成的结