Objectives
After completing this lesson,you should be able to do the following:
- Define subqueries.
- Describe the types of problems that the subqueries can solve.
- List the types of subqueries.
- Write single-row and multiple-row subqueries.
single-row:查询结果返回一条记录
multiple-row: 查询结果返回多条记录
Lesson Agenda
- Subquery:Types,syntax,and guidelines
- Single-row subqueries
- -Group functions in a subquery
- -HAVING clause with subqueries
- Multiple-row subqueries
- -Use ALL or ANY operator
Using a Subquery to Solve a Problem
Who has a salary greater than Abel`s?
Demo-01:
Original Query
SQL> SELECT employee_id,first_name,last_name,salary FROM employees WHERE last_name LIKE 'Abel%'; EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY ----------- -------------------- ------------------------- ---------- 174 Ellen Abel 11000 SQL> SELECT employee_id,first_name,last_name,salary FROM employees WHERE salary > 11000; EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY ----------- -------------------- ------------------------- ---------- 201 Michael Hartstein 13000 205 Shelley Higgins 12008 100 Steven King 24000 101 Neena Kochhar 17000 102 Lex De Haan 17000 108 Nancy Greenberg 12008 145 John Russell 14000 146 Karen Partners 13500 147 Alberto Errazuriz 12000 168 Lisa Ozer 11500 10 rows selected.
Subquery Syntax
SELECT select_list FROM table WHERE expr operator (SELECT select_list FROM table);
注意:operator的具体值取决于subquery result,视子查询的返回结果集来判断具体使用哪一个Operator.
- The subquery(inner query) executes before the main query(outer query)
- The result of the subquery is used by the main query
subquery 一般应用在from where having clause.
Using a Subquery
Subquery
SQL> SELECT employee_id,first_name,last_name,salary 2 FROM employees 3 WHERE salary > (SELECT salary FROM employees WHERE last_name LIKE 'Abel%'); EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY ----------- -------------------- ------------------------- ---------- 201 Michael Hartstein 13000 205 Shelley Higgins 12008 100 Steven King 24000 101 Neena Kochhar 17000 102 Lex De Haan 17000 108 Nancy Greenberg 12008 145 John Russell 14000 146 Karen Partners 13500 147 Alberto Errazuriz 12000 168 Lisa Ozer 11500 10 rows selected.
Subquery Error`s Demo
SQL> SELECT employee_id,first_name,last_name,salary 2 FROM employees 3 WHERE salary > (SELECT salary FROM employees WHERE last_name LIKE 'K%'); WHERE salary > (SELECT salary FROM employees WHERE last_name LIKE 'K%') * ERROR at line 3: ORA-01427: single-row subquery returns more than one row
Gudelines for Using Subqueries
- Enclose subqueries in parentheses.
- Place subqueries on the right side of the comparison condition for readbility(However,the query can appear on either side of the comparison operator.).
- Use single-row operators with single-row subqueries and multiple-row operators with multiple-row subqueries.
Types of Subqueries
Single-Row Subqueries
- Return only one row
- Use single-row comparison operators
Operator | Meaning |
= | Equal to |
> | Greater than |
>= | Greater than or equal to |
< | Less than |
<= | Less than or equal to |
<> | Not equal to |
Demo
SQL> SELECT last_name,job_id 2 FROM employees 3 WHERE job_id = 4 (SELECT job_id 5 FROM employees 6 WHERE employee_id=141); LAST_NAME JOB_ID ------------------------- ---------- Nayer ST_CLERK Mikkilineni ST_CLERK Landry ST_CLERK Markle ST_CLERK Bissot ST_CLERK Atkinson ST_CLERK Marlow ST_CLERK Olson ST_CLERK Mallin ST_CLERK Rogers ST_CLERK Gee ST_CLERK LAST_NAME JOB_ID ------------------------- ---------- Philtanker ST_CLERK Ladwig ST_CLERK Stiles ST_CLERK Seo ST_CLERK Patel ST_CLERK Rajs ST_CLERK Davies ST_CLERK Matos ST_CLERK Vargas ST_CLERK 20 rows selected.
Executing Single-Row Subqueries
View Code
SELECT last_name,job_id,salary FROM employees WHERE job_id = ( SELECT job_id FROM employees WHERE last_name = 'Taylor' AND job_id LIKE '%SA_REP%' ) AND salary > ( SELECT salary FROM employees WHERE last_name = 'Taylor' AND job_id LIKE '%SA_REP%' ); LAST_NAME JOB_ID SALARY ------------------------- ---------- ---------- Tucker SA_REP 10000 Bernstein SA_REP 9500 Hall SA_REP 9000 King SA_REP 10000 Sully SA_REP 9500 McEwen SA_REP 9000 Vishney SA_REP 10500 Greene SA_REP 9500 Ozer SA_REP 11500 Bloom SA_REP 10000 Fox SA_REP 9600 LAST_NAME JOB_ID SALARY ------------------------- ---------- ---------- Abel SA_REP 11000 Hutton SA_REP 8800 13 rows selected.
Using Group Functions in a Subqueries
View Code
SELECT last_name,job_id,salary FROM employees WHERE salary = (SELECT MIN(salary) FROM employees ); LAST_NAME JOB_ID SALARY ------------------------- ---------- ---------- Olson ST_CLERK 2100
The HAVING Clause with Subqueries
The Oracle server executes the subqueries first.
The Oracle server returns into the HAVING clause of the main query.
View Code
SELECT department_id,min(salary) FROM employees GROUP BY department_id HAVING MIN(salary) > ( SELECT MIN(salary) FROM employees WHERE department_id = 50 ); DEPARTMENT_ID MIN(SALARY) ------------- ----------- 100 6900 30 2500 7000 20 6000 70 10000 90 17000 110 8300 40 6500 80 6100 10 4400 60 4200 11 rows selected.
Demo 02
SELECT job_id,avg(salary) FROM employees GROUP BY job_id HAVING avg(salary) = ( SELECT min(avg(salary)) FROM employees GROUP BY job_id ); JOB_ID AVG(SALARY) ---------- ----------- PU_CLERK 2780
Wrong Subquery Demo
SELECT employee_id,last_name FROM employees 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
No Rows Returned by the lnner Query
Demo01-仔细对比
SELECT last_name,job_id FROM employees WHERE job_id = ( SELECT job_id FROM employees WHERE last_name = 'Hass' ); no rows selected
Demo02-subqueries return null value
SELECT employee_id,last_name,job_id,department_id FROM employees WHERE department_id = ( SELECT department_id FROM employees WHERE last_name = 'Grant' AND job_id = 'SA_REP' ); no rows selected
Demo02结果分析:subquery result is null value,operator '=' is a arithmeic expression.所以,只要=运算中出现NULL VALUE,那么整个表达式的值,都将为NULL.那么在where子句中,NULL值视同为FALSE.所以整个Main Query的结果为:no rows selected.
Mutltiple-Row Subqueries
- Return more than one row.
- Use multiple-row comparison operators
Operator | Menaing |
IN | Equal to any member in the list |
ANY | Must be preceded by =,!=,>,<,<=,>=.Compares a value to each value in a list or returned by a query.Evaluates to FALUSE if the query returns no rows. |
ALL | Must be preceded by =,!=,>,<,<=,<=.Compares a value to every value in a list or returned by a query.Evaluates to TRUE if the query returns no rows. |
Using the ANY Operator in Multiple-Row Subqueries
Any Keyword
SQL> SELECT salary FROM employees WHERE job_id = 'IT_PROG'; SALARY ---------- 9000 6000 4800 4800 4200 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') 4 AND job_id <> 'IT_PROG'; EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 132 Olson ST_CLERK 2100 136 Philtanker ST_CLERK 2200 128 Markle ST_CLERK 2200 135 Gee ST_CLERK 2400 127 Landry ST_CLERK 2400 119 Colmenares PU_CLERK 2500 191 Perkins SH_CLERK 2500 182 Sullivan SH_CLERK 2500 144 Vargas ST_CLERK 2500 140 Patel ST_CLERK 2500 131 Marlow ST_CLERK 2500 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 143 Matos ST_CLERK 2600 118 Himuro PU_CLERK 2600 198 OConnell SH_CLERK 2600 199 Grant SH_CLERK 2600 126 Mikkilineni ST_CLERK 2700 139 Seo ST_CLERK 2700 183 Geoni SH_CLERK 2800 195 Jones SH_CLERK 2800 130 Atkinson ST_CLERK 2800 117 Tobias PU_CLERK 2800 134 Rogers ST_CLERK 2900 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 116 Baida PU_CLERK 2900 190 Gates SH_CLERK 2900 187 Cabrio SH_CLERK 3000 197 Feeney SH_CLERK 3000 115 Khoo PU_CLERK 3100 196 Walsh SH_CLERK 3100 142 Davies ST_CLERK 3100 181 Fleaur SH_CLERK 3100 194 McCain SH_CLERK 3200 138 Stiles ST_CLERK 3200 125 Nayer ST_CLERK 3200 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 180 Taylor SH_CLERK 3200 133 Mallin ST_CLERK 3300 129 Bissot ST_CLERK 3300 186 Dellinger SH_CLERK 3400 141 Rajs ST_CLERK 3500 189 Dilly SH_CLERK 3600 137 Ladwig ST_CLERK 3600 188 Chung SH_CLERK 3800 193 Everett SH_CLERK 3900 192 Bell SH_CLERK 4000 185 Bull SH_CLERK 4100 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 184 Sarchand SH_CLERK 4200 200 Whalen AD_ASST 4400 124 Mourgos ST_MAN 5800 202 Fay MK_REP 6000 173 Kumar SA_REP 6100 179 Johnson SA_REP 6200 167 Banda SA_REP 6200 166 Ande SA_REP 6400 123 Vollman ST_MAN 6500 203 Mavris HR_REP 6500 165 Lee SA_REP 6800 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 113 Popp FI_ACCOUNT 6900 178 Grant SA_REP 7000 161 Sewall SA_REP 7000 155 Tuvault SA_REP 7000 164 Marvins SA_REP 7200 172 Bates SA_REP 7300 171 Smith SA_REP 7400 160 Doran SA_REP 7500 154 Cambrault SA_REP 7500 111 Sciarra FI_ACCOUNT 7700 112 Urman FI_ACCOUNT 7800 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 122 Kaufling ST_MAN 7900 159 Smith SA_REP 8000 120 Weiss ST_MAN 8000 153 Olsen SA_REP 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.
解读:> ANY就相当于大于子查询中的最小值;
< ANY就相当于小于子查询中的最大值;
= ANY就相当于关键字IN;
> ANY
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'); EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 100 King AD_PRES 24000 101 Kochhar AD_VP 17000 102 De Haan AD_VP 17000 145 Russell SA_MAN 14000 146 Partners SA_MAN 13500 201 Hartstein MK_MAN 13000 205 Higgins AC_MGR 12008 108 Greenberg FI_MGR 12008 147 Errazuriz SA_MAN 12000 168 Ozer SA_REP 11500 148 Cambrault SA_MAN 11000 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 174 Abel SA_REP 11000 114 Raphaely PU_MAN 11000 162 Vishney SA_REP 10500 149 Zlotkey SA_MAN 10500 169 Bloom SA_REP 10000 156 King SA_REP 10000 150 Tucker SA_REP 10000 204 Baer PR_REP 10000 170 Fox SA_REP 9600 151 Bernstein SA_REP 9500 157 Sully SA_REP 9500 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 163 Greene SA_REP 9500 103 Hunold IT_PROG 9000 109 Faviet FI_ACCOUNT 9000 152 Hall SA_REP 9000 158 McEwen SA_REP 9000 175 Hutton SA_REP 8800 176 Taylor SA_REP 8600 177 Livingston SA_REP 8400 206 Gietz AC_ACCOUNT 8300 110 Chen FI_ACCOUNT 8200 121 Fripp ST_MAN 8200 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 120 Weiss ST_MAN 8000 153 Olsen SA_REP 8000 159 Smith SA_REP 8000 122 Kaufling ST_MAN 7900 112 Urman FI_ACCOUNT 7800 111 Sciarra FI_ACCOUNT 7700 160 Doran SA_REP 7500 154 Cambrault SA_REP 7500 171 Smith SA_REP 7400 172 Bates SA_REP 7300 164 Marvins SA_REP 7200 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 155 Tuvault SA_REP 7000 161 Sewall SA_REP 7000 178 Grant SA_REP 7000 113 Popp FI_ACCOUNT 6900 165 Lee SA_REP 6800 123 Vollman ST_MAN 6500 203 Mavris HR_REP 6500 166 Ande SA_REP 6400 167 Banda SA_REP 6200 179 Johnson SA_REP 6200 173 Kumar SA_REP 6100 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 202 Fay MK_REP 6000 104 Ernst IT_PROG 6000 124 Mourgos ST_MAN 5800 106 Pataballa IT_PROG 4800 105 Austin IT_PROG 4800 200 Whalen AD_ASST 4400 61 rows selected.
= ANY
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'); EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 158 McEwen SA_REP 9000 152 Hall SA_REP 9000 109 Faviet FI_ACCOUNT 9000 103 Hunold IT_PROG 9000 104 Ernst IT_PROG 6000 202 Fay MK_REP 6000 106 Pataballa IT_PROG 4800 105 Austin IT_PROG 4800 184 Sarchand SH_CLERK 4200 107 Lorentz IT_PROG 4200 10 rows selected.
Using the ALL Operator in Multiple-Row subqueries
解读:> ALL就相当于大于子查询中的最大值
< ALL就相当于小于子查询中的最小值
没有等于ALL ^^
All Keywords
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 ----------- ------------------------- ---------- ---------- 185 Bull SH_CLERK 4100 192 Bell SH_CLERK 4000 193 Everett SH_CLERK 3900 188 Chung SH_CLERK 3800 137 Ladwig ST_CLERK 3600 189 Dilly SH_CLERK 3600 141 Rajs ST_CLERK 3500 186 Dellinger SH_CLERK 3400 133 Mallin ST_CLERK 3300 129 Bissot ST_CLERK 3300 180 Taylor SH_CLERK 3200 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 125 Nayer ST_CLERK 3200 138 Stiles ST_CLERK 3200 194 McCain SH_CLERK 3200 115 Khoo PU_CLERK 3100 142 Davies ST_CLERK 3100 196 Walsh SH_CLERK 3100 181 Fleaur SH_CLERK 3100 187 Cabrio SH_CLERK 3000 197 Feeney SH_CLERK 3000 116 Baida PU_CLERK 2900 190 Gates SH_CLERK 2900 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 134 Rogers ST_CLERK 2900 195 Jones SH_CLERK 2800 183 Geoni SH_CLERK 2800 117 Tobias PU_CLERK 2800 130 Atkinson ST_CLERK 2800 139 Seo ST_CLERK 2700 126 Mikkilineni ST_CLERK 2700 118 Himuro PU_CLERK 2600 199 Grant SH_CLERK 2600 143 Matos ST_CLERK 2600 198 OConnell SH_CLERK 2600 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 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 140 Patel 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.
> ALL
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 ----------- ------------------------- ---------- ---------- 157 Sully SA_REP 9500 151 Bernstein SA_REP 9500 163 Greene SA_REP 9500 170 Fox SA_REP 9600 204 Baer PR_REP 10000 169 Bloom SA_REP 10000 156 King SA_REP 10000 150 Tucker SA_REP 10000 162 Vishney SA_REP 10500 149 Zlotkey SA_MAN 10500 148 Cambrault SA_MAN 11000 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 174 Abel SA_REP 11000 114 Raphaely PU_MAN 11000 168 Ozer SA_REP 11500 147 Errazuriz SA_MAN 12000 108 Greenberg FI_MGR 12008 205 Higgins AC_MGR 12008 201 Hartstein MK_MAN 13000 146 Partners SA_MAN 13500 145 Russell SA_MAN 14000 102 De Haan AD_VP 17000 101 Kochhar AD_VP 17000 EMPLOYEE_ID LAST_NAME JOB_ID SALARY ----------- ------------------------- ---------- ---------- 100 King AD_PRES 24000 23 rows selected.
= ALL (逻辑上是混乱的,但是没有报错)
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'; no rows selected
Null Values in a Subquery
SELECT emp.last_name FROM employees emp WHERE emp.employee_id NOT IN ( SELECT mgr.manager_id FROM employees mgr );
NULL VALUR -> NOT IN
SQL> SELECT emp.last_name 2 FROM employees emp 3 WHERE emp.employee_id NOT IN (SELECT mgr.manager_id FROM employees mgr); no rows selected
NULL VALUE -> IN
SQL> SELECT emp.last_name 2 FROM employees emp 3 WHERE emp.employee_id IN (SELECT mgr.manager_id FROM employees mgr); LAST_NAME ------------------------- Cambrault De Haan Errazuriz Fripp Greenberg Hartstein Higgins Hunold Kaufling King Kochhar LAST_NAME ------------------------- Mourgos Partners Raphaely Russell Vollman Weiss Zlotkey 18 rows selected.
NOT IN -> "不等于ALL"
IN -> "等于ANY"
以上两者(NOT IN,IN)在遇上NULL VALUE的时候,表现结果是大相径庭的.
Summary
In this lesson,you should have learned how to:
- Identify when a subquery can help solve a problem.
- Wrtie subqueries when a query is based on unknow values.
SELECT select_list FROM table WHERE expr operator ( SELECT select_list FROM table );