ПОДЗАПРОСЫ Что такое подзапрос? Подзапрос - это команда SELECT, вложенная в предложение другой команды SQL. Главный запрос Синтаксис команды Select Select… Синтаксис From… Select Where… (Select… From… Where…) Подзапрос Подзапросы: синтаксис SELECT select_list FROM table WHERE expr operator (SELECT select_list FROM table); Подзапрос выполняется до выполнения главного запроса. Результат подзапроса используется главным внешним запросом. Указания по использованию подзапросов Подзапрос должен быть заключен в скобки. В подзапросах используются операторы сравнения двух типов: однострочные и многострочные. Подзапрос должен находиться справа от оператора. Подзапросы могут использоваться во многих командах SQL. Подзапросы не могут содержать предложение ORDER BY. ПРЕДЛОЖЕНИЯ КОМАНДЫ SELECT, В КОТОРЫХ ИСПОЛЬЗУЮТСЯ ПОДЗАПРОСЫ WHERE HAVING FROM Подзапросы: пример LAST_NAME TITLE -------------- ----------Maduro Stock Clerk Smith Stock Clerk Nozaki Stock Clerk Patel Stock Clerk Newman Stock Clerk Chang Stock Clerk Patel Stock Clerk Danca Stock Clerk Schwartz Stock Clerk TITLE ----------Stock Clerk LAST_NAME ----------Smith Как обрабатываются вложенные подзапросы? 1 2 Вложенная команда SELECT выполняется первой. Результат передается в условие главного запроса. Вложенный запрос SELECT dept_id FROM s_emp WHERE last_name='Biri' Главный запрос SELECT last_name, title FROM s_emp WHERE dept_id = Предложение HAVING с подзапросами Подзапросы используются и в предложениях HAVING. Сервер Oracle выполняет подзапросы первыми. Сервер возвращает результаты в предложение HAVING главного запроса. SQL> SELECT dept_id, AVG(salary) 2 FROM s_emp 3 GROUP ВY dept_id 4 HAVING AVG(salary) > 5 (SELECT AVG(salary) 6 FROM s_emр 7 WHERE dept_id = 32) ; Однострочные подзапросы SELECT last_name,title FROM s_emp WHERE title = Команда SQL для вывода фамилии и должности служащего SELECT title FROM s_emp WHERE last_name = ‘Smith’ SQL> 2 3 4 5 6 Команда SQL дпя выяснения должности сотрудника с фамилией Smith Соедините обе команды, и пусть SQL определит должность сотрудника с фамилией Smith. SELECT last_name, title FROM s_emp WHERE title = (SELECT title FROM s_emp WHERE last_name = ‘Smith’); Пример Вывод фамилии, должности и заработной платы всех сотрудников с заработной платой ниже средней. SQL> SELECT last_name, title, salary 2 FROM s_emp 3 WHERE salary < 4 (SELECT AVG (salary) 5 FROM s_emp); LAST_NAME TITLE SALARY ---------------- ----------------- -----Urguhart Warehouse Manager 1200 Menchu Warehouse Manager 1250 Biri Warehouse Manager 1100 Smith Stock Clerk 940 Nozaki Stock Clerk 1200 Patel Stock Clerk 795 Newman Stock Clerk 750 Markarian Stock Clerk 850 Chang Stock Clerk 800 Patel Stock Clerk 795 Danes Stock Clerk 860 Schwartz Stock Clerk 1100 12 rows selected. Многострочные подзапросы • Возвращают более одной строки • Используют многострочные операторы сравнения Оператор Значение IN Сравнение с любым элементом списка по знаку сравнения «=» ANY | SOME Сравнение с любым значением, возвращаемым подзапросом, по заданному знаку сравнения ALL Сравнение со всеми значениями, возвращаемыми подзапросом, по заданному знаку сравнения Ошибки в подзапросах Если пишется подзапрос, возвращающий более одной строки, и в нем используется однострочный оператор сравнения, выдается сообщение об ошибке. SQL> SELECT last_name, first_name, title 2 FROM e_emp 3 WHERE dept_id = 4 (SELECT ID 5 FROM s_dept 6 WHERE name = 'Finance’ 7 OR region_id = 2) ; ORA-01427:single-row subquery returns more than one row Для исправления измените этот оператор на (многострочный оператор сравнения). Многострочные подзапросы: пример Вместо оператора IN используется оператор =ANY. SQL> SELECT last_name, first_name, title 2 FROM s_emp 3 WHERE dept_id = ANY 4 (SELECT ID 5 FROM s_dept 6 WHERE name = 'Finance' 7 OR region_id = 2) ; Использование оператора ANY в многострочных подзапросах SQL> 2 3 4 5 6 7 SELECT empno, ename, job FROM emp WHERE sal<ANY (SELECT sal FROM emp WHERE job = ‘CLERK’) AND job <> ‘CLERK’; EMPNO ------7654 7521 ENAME ----------MARTIN WARD JOB -----SALESMAN SALASMAN Использование оператора ALL в многострочных подзапросах SQL> SELECT empno, ename, job 2 FROM emp 3 WHERE sal>ALL 4 (SELECT avg(sal ) 5 FROM emp 6 GROUP BY deptno); EMPNO ------7839 7566 7902 7788 ENAME ----------KING JONES FORD SCOTT JOB -----PRESIDENT MANAGER ANALYST ANALYST Многостолбцовые подзапросы Главный запрос MANAGER 10 Подзапрос SALESMAN 30 MANAGER 10 CLERK 20 Главный запрос производит сравнение MANAGER 10 с значениями из многострочного и многостолбцового подзапроса SALESMAN MANAGER CLARK 30 10 20 Использование многостолбцовых подзапросов Вывод фамилии, номера отдела, оклада и комиссионных всех служащих, оклад и комиссионные которых совпадают как с окладом, так и с комиссионными одного и того же служащего в отделе 30. SQL> SELECT ename, deptno, sal, comm 2 FROM emp 3 WHERE (sal, NVL(comm,-1)) IN 4 (SELECT sal, NVL(comm,-1) 5 FROM emp 6 WHERE deptno = 30); Сравнение столбцов Парное SAL 1600 1250 1250 2850 1500 950 Непарное COMM 300 500 1400 0 SAL 1600 1250 1250 2850 1500 950 COMM 300 500 1400 0 Подзапрос с непарным сравнением Вывод фамилии, номера отдела, оклада и комиссионных всех служащих, оклад и комиссионные которых совпадают с комиссионными и окладом любого служащего в отделе 30. SQL> SELECT ename, deptno, sal, comm 2 FROM emp 3 WHERE sal IN (SELECT sal 4 FROM emp 5 WHERE deptno = 30) 6 AND 7 NVL(comm, -1) IN (SELECT NVL(comm,-1) 8 FROM emp 9 WHERE deptno=30); Изменения таблицы EMP Предположим, что изменяются оклады комиссионные Кларка (Clark). Новый оклад - до 1500 долларов, в новые комиссионные - до 300 долларов. SAL ENAME COMM --------------… CLARK 1500 … ALLEN 1600 TURNER 1500 … 14 rows selected. -----300 300 0 Подзапросы с парным сравнением SQL> SELECT ename, deptno, sal, comm 2 FROM emp 3 WHERE (sal, NVL(comm, -1)) IN 4 (SELECT sal, NVL(comm, -1) 5 FROM emp 6 WHERE deptno = 30); ENAME DEPTNO ---------JAMES 30 WARD 30 MARTIN 30 TURNER 30 ALLEN 30 BLAKE 30 6 rows selected. SAL --950 1250 1250 1500 1600 2850 COMM ---500 1400 0 300 Подзапросы с непарным сравнением SQL> 2 3 4 5 6 7 8 9 SELECT ename, deptno, sal, comm FROM emp WHERE sal IN (SELECT sal FROM emp WHERE deptno = 30) AND NVL(comm, -1) IN (SELECT NVL(comm, -1) FROM emp WHERE deptno = 30); ENAME DEPTNO ---------JAMES 30 BLAKE 30 TURNER 30 CLARK 30 ... 7 rows selected. SAL --950 2850 1500 1500 COMM ---- 0 300 Неопределенное значение в подзапросе SQL> SELECT employee.ename 2 FROM emp employee 3 WHERE employee.empno NOT IN 4 (SELECT manager.mgr 5 FROM emp manager); no rows selected. Использование подзапроса в предложении FROM SQL> 2 3 4 5 6 SELECT a.ename, a.deptno, b.salavg FROM emp a, (SELECT deptno, avg(sal) salavg FROM emp GROUP BY deptno) b WHERE a.deptno = b.deptno AND a.sal > b.salavg; ENAME SAL ---------KING 5000 JONES 2975 SCOTT 3000 ... 6 rows selected. DAPTNO --10 20 20 SALAVG ---2916.6667 2175 2175 Коррелированные подзапросы: синтаксис Внутренний подзапрос ссылается на внешний запрос Выполнение начинается с внешнего запроса SELECT select_list FROM table1 t_alias1 WHERE expr operator (SELECT column_list FROM table2 t_alias2 WHERE t_alias1.column operator t_alias2.column); Коррелированные подзапросы: пример Внутренний подзапрос ссылается на внешний запрос Выполнение начинается с внешнего запроса SQL> 2 3 4 5 6 SELECT deptno, ename, sal FROM emp x WHERE sal > (SELECT AVG(sal) FROM emp WHERE x.deptno = deptno) ORDER BY deptno; Квантифицированные подзапросы Использование операторов EXISTS и NOT EXISTS Внешний запрос выполняется, если внутренний подзапрос возвращает хотя бы одну строку SQL> SELECT dname, deptno 2 FROM dept 3 WHERE NOT EXISTS 4 (SELECT * FROM emp 5 WHERE dept.deptno = emp.deptno); Заключение Подзапросы полезны для выборки данных по неизвестным значениям. Вложенный запрос содержит более одного предложения SELECT. Подзапросы обрабатываются первыми, после чего выполняется основной запрос по результатам подзапроса, переданным в предложение WHERE или HAVING. SELECT select_list FROM table WHERE expr operator (SELECT select_list FROM table);