W 3 Resource
W 3 Resource
Home
Frontend
Backend
SQL & RDBMS
NoSQL
Data-interchange
API & Tools
Exercises
▼Subqueries
Understanding Subqueries
Single Row Subqueries
Multiple Row and Column Subqueries
Correlated subqueries using aliases
Nested subqueries
Description
A subquery can be nested inside other subqueries. SQL has an ability to nest
queries within one another. A subquery is a SELECT statement that is nested
within another SELECT statement and which return intermediate results. SQL
executes innermost subquery first, then next level. See the following examples :
Example -1 : Nested subqueries
If we want to retrieves those unique job_id and there average salary from the
employees table which unique job_id have a salary is smaller than (the maximum
of averages of min_salary of each unique job_id from the jobs table which job_id
are in the list, picking from (the job_history table which are within the
department_id 50 and 100)) the following SQL statement can be used :
1. SELECT job_id,AVG(salary)
2. FROM employees
3. GROUP BY job_id
4. HAVING AVG(salary)<
5. (SELECT MAX(AVG(min_salary))
6. FROM jobs
7. WHERE job_id IN
8. (SELECT job_id FROM job_history
9. WHERE department_id
10.BETWEEN 50 AND 100)
11.GROUP BY job_id);
Output
Explanation :
This example contains three queries: a nested subquery, a subquery and the
outer query. These parts of queries are runs in that order.
Let's break the example down into three parts and observes the results returned.
At first the nested subquery as follows:
view plaincopy to clipboardprint?
1. SELECT job_id FROM job_history
2. WHERE department_id
3. BETWEEN 50 AND 100;
This nested subquery retrieves the job_id(s) from job_history table which are
within the department_id 50 and 100.
Here is the output.
Output
Here is the pictorial representation of how the above output cames.
Now the subquery that receives output from the nested subquery stated above.
SELECT MAX(AVG(min_salary))
GROUP BY job_id
1. SELECT MAX(AVG(min_salary))
2. FROM jobs
3. WHERE job_id
4. IN(
5. 'ST_CLERK','ST_CLERK','IT_PROG',
6. 'SA_REP','SA_MAN','AD_ASST', '
7. AC_ACCOUNT')
8. GROUP BY job_id;
The subquery returns the maximum of averages of min_salary for each unique
job_id return ( i.e. 'ST_CLERK','ST_CLERK','IT_PROG',
'SA_REP','SA_MAN','AD_ASST', 'AC_ACCOUNT' ) by the previous subquery.
Here is the output:
Output
FROM employees
GROUP BY job_id
HAVING AVG(salary)<
The outer query returns the job_id, average salary of employees that are less
than maximum of average of min_salary returned by the previous query
1. SELECT ord_num,ord_date,ord_amount,advance_amount
2. FROM orders
3. WHERE ord_amount>2000
4. AND ord_date<'01-SEP-08'
5. AND ADVANCE_AMOUNT <
6. ANY(SELECT OUTSTANDING_AMT
7. FROM CUSTOMER
8. WHERE GRADE=3
9. AND CUST_COUNTRY<>'India'
10.AND opening_amt<7000
11.AND EXISTS
12.(SELECT *
13.FROM agents
14.WHERE commission<.12));
Output
Explanation :
The last Inner query will fetched the rows from agents table who have
commission is less than .12%.
The 2nd last inner query returns the outstanding amount for those customer who
are in grade 3 and not belongs to the country India and their deposited opening
amount is less than 7000 and their agents should have earned a commission is
less than .12%.
The outer query returns ord_num, ord_date, ord_amount, advance_amount for
those orders from orders table which ord_amount is more than 2000 and
ord_date before the '01-sep-08' and the advance amount may be the outstanding
amount for those customer who are in grade 3 and not belongs to the country
India and there deposited opening amount is less than 7000 and their agents
should have earned a commission is less than .12%.
Let's break the code and analyze what's going on in inner query. Here is the first
code of inner query with output :
view plaincopy to clipboardprint?
1. SELECT *
2. FROM agents
3. WHERE commission<.12;
Output
Here is the second code of inner query (including first one) with output :
view plaincopy to clipboardprint?
1. SELECT OUTSTANDING_AMT
2. FROM CUSTOMER
3. WHERE GRADE=3
4. AND CUST_COUNTRY<>'India'
5. AND opening_amt<7000
6. AND EXISTS
7. SELECT *
8. FROM agents
9. WHERE commission<.12);
Introduction
A subquery is a SQL query nested inside a larger query.
A subquery may occur in :
- A SELECT clause
- A FROM clause
- A WHERE clause
The subquery can be nested inside a SELECT, INSERT, UPDATE, or DELETE statement or
inside another subquery.
A subquery is usually added within the WHERE Clause of another SQL SELECT statement.
You can use the comparison operators, such as >, <, or =. The comparison operator can also be
a multiple-row operator, such as IN, ANY, or ALL.
A subquery can be treated as an inner query, which is a SQL query placed as a part of another
query called as outer query.
The inner query executes first before its parent query so that the results of inner query can be
passed to the outer query.
Syntax :
The subquery (inner query) executes once before the main query (outer query) executes.
The main query (outer query) use the subquery result.
student marks
Now we want to write a query to identify all students who get better marks than
that of the student who's StudentID is 'V002', but we do not know the marks of
'V002'.
- To solve the problem, we require two queries. One query returns the marks
(stored in Total_marks field) of 'V002' and a second query identifies the students
who get better marks than the result of the first query.
First query :
view plaincopy to clipboardprint?
1. SELECT *
2. FROM `marks`
3. WHERE studentid = 'V002';
Query result :
1. SELECT a.studentid, a.name, b.total_marks
2. FROM student a, marks b
3. WHERE a.studentid = b.studentid
4. AND b.total_marks >80;
Query result :
Above two queries identified students who get better number than the student
who's StudentID is 'V002' (Abhay).
You can combine the above two queries by placing one query inside the other.
The subquery (also called the 'inner query') is the query inside the parentheses.
See the following code and query result :
view plaincopy to clipboardprint?
1. SELECT a.studentid, a.name, b.total_marks
2. FROM student a, marks b
3. WHERE a.studentid = b.studentid AND b.total_marks >
4. (SELECT total_marks
5. FROM marks
6. WHERE studentid = 'V002');
Query result :
Pictorial Presentation of SQL Subquery :
[WHERE search_conditions]
[HAVING search_conditions])
Subqueries: Guidelines
There are some guidelines to consider when using subqueries :
- A subquery must be enclosed in parentheses.
- A subquery must be placed on the right side of the comparison operator.
- Subqueries cannot manipulate their results internally, therefore ORDER BY
clause cannot be added in to a subquery.You can use a ORDER BY clause in
the main SELECT statement (outer query) which will be last clause.
- Use single-row operators with single-row subqueries.
- If a subquery (inner query) returns a null value to the outer query, the outer
query will not return any rows when using certain comparison operators in a
WHERE clause.
Type of Subqueries
- Single row subquery : Returns zero or one row.
- Multiple row subquery : Returns one or more rows.
- Multiple column subquery : Returns one or more columns.
- Correlated subqueries : Reference one or more columns in the outer SQL
statement. The subquery is known as a correlated subquery because the
subquery is related to the outer SQL statement.
- Nested subqueries : Subqueries are placed within another subqueries.
In the next session we have thoroughly discussed the above topics. Apart from
the above type of subqueries you can use subquery inside INSERT, UPDATE
and DELETE statement. Here is a brief discussion :
If we want to insert those orders from 'orders' table which have the
advance_amount 2000 or 5000 into 'neworder' table the following SQL can be
used:
Sample table : orders
view plaincopy to clipboardprint?
1. INSERT INTO neworder
2. SELECT * FROM orders
3. WHERE advance_amount in(2000,5000);
Output
(SELECT COLUMN_NAME
FROM TABLE_NAME)
[ WHERE) ]
1. UPDATE neworder
2. SET ord_date='15-JAN-10'
3. WHERE ord_amount-advance_amount<
4. (SELECT MIN(ord_amount) FROM orders);
(SELECT COLUMN_NAME
FROM TABLE_NAME)
[ WHERE) ]
1. DELETE FROM neworder
2. WHERE advance_amount<
3. (SELECT MAX(advance_amount) FROM orders);