Subquery ORACLE
Subquery ORACLE
To illustrate the SUBQUERY, we consider the instances of the following tables to illustrate this
section.
EMP table:
DEPT table:
PROJECT table:
ASSIGN table:
ECODE PID
----- -----
E01 P01
E01 P02
E01 P03
E02 P01
E08 P01
E02 P02
E08 P02
E07 P02
E03 P03
E09 P03
E06 P03
Query: Find the employees who are working in department located at KOLKATA.
Using non-correlated subquery the SQL statement will be:
OUTER QUERY
INNER QUERY
Inner query is independent gets executed first, passes results to the outer query. Using correlated
subquery the above one can be rewritten as-
SELECT ecode, ename, dno
FROM emp outer
WHERE dno IN (SELECT dno FROM dept WHERE city = ‘KOLKATA’
AND dno =outer.dno);
Output:
6 rows selected.
Correlated sub queries operate in a repetitive manner. Those familiar with looping control
structures of a programming language will see the similarity. In a correlated sub query, the outer
Relaxed Query
SELECT ecode, ename, dno FROM emp;
Test records
ECODE ENAME DNO
----- ------------------------------ -----
E01 KOUSHIK GHOSH D01
E02 JAYANTA DUTTA D01
E03 HARI NANDAN TUNGA D02
E04 JAYANTA GANGULY D03
E05 RAJIB HALDER D03
E06 JISHNU BANERJEE D02
E07 RANI BOSE D01
E08 GOUTAM DEY D01
E09 PINAKI BOSE D02
9 rows selected.
Step 1 First the outer query runs and supplies a column from the first test record to the inner
query
Step 2 Then the outer query shares the outer.dno column value of ‘D01’ with the inner query and
the inner query runs. Let’s see the result of the inner query.
SELECT dno
DNO
FROM dept Column outer.dno is supplied to the -----------
WHERE city = ‘KOLKATA’ inner query. The inner query runs and D01
produces the result set on the right.
AND dno = ‘D01’;
Step 3 The inner query can now provide a value to the outer query’s WHERE clause. Now the
outer query can evaluate the comparison condition in the WHERE clause. Notice that we have to
Step 4 The outer query has found a match so E01’s information is returned.
Continue Step 1 through Step 4 for each record in the test record set.
As we have seen, a simple subquery is executed once prior to the execution of the outer query.
With a correlated subquery, the inner query is executed once for each record that is returned by
the outer query. The inner query is driven by a correlation between the outer query and the inner
query. The correlation provided by an exchange of column(s) from the outer query to the inner
query. A table alias is used to share the outer query column(s) with the inner query.
The general form of subquery is as follows-
PREDICATE SUBQUERIES
Predicate subqueries are used in the WHERE (and HAVING) clause. Each is a special logical
construct. Predicate subqueries may be classified into following categories-
The following generic SELECT statement depicts the syntax for a simple subquery returning a
single value.
SELECT <column_list>
FROM <table_list>
WHERE COLUMN <relational_operator> (SELECT statement);
Illustration:
A) NON-CORRELATED SUBQUERY
Query: Retrieve the names and salaries for all employees who earn more than the average
salary.
• Non-Correlated subquery in HAVING - Selecting ONLY the group with the maximum Sum in
a group query
Query: Display the name of the department and sum of salaries of all employees of that
department which is spending maximum sum of salaries.
DNAME SUM(B.SALARY)
------------------------------ -------------
PROJECT 16500
Query: List the employees who get the same salary as KOUSHIK GHOSH
Query: List the details of the employees getting highest salary in each department
• Listing a certain number of records with the highest values for a certain column using
SQL Only.
There are times where it is needed to simply return the rows with a certain number of the highest
(or lowest) values for a certain column. For example,
Query: Display the code and salary of the first three employees getting highest salaries.
One solution for this problem is to use a correlated subquery to the same table. The following
select will return the correct rows:
SELECT ecode, salary FROM emp e1
WHERE 3 > (SELECT COUNT(*) FROM emp e2 WHERE e1.salary < e2.salary)
ORDER BY salary desc ;
For every row processed by the main query, the correlated subquery returns a count (COUNT(*) )
of the number of rows with higher salaries (WHERE e1.salary < e2.salary). Then the main query
only returns rows that have fewer than three salaries that are higher (WHERE 3 > ...). For
example, for ECODE=E09, the salary is "5500". There is only 2 rows with a higher salary
(ECODE=E06, E04), so the subquery returns "2", which is less than 3, causing the "WHERE 3 >
..." to evaluate to TRUE, thereby returning the row.
SALARY
----------
5500
Query: Display the details of the employee(s) getting third highest salary.
SELECT * FROM emp WHERE salary =( SELECT DISTINCT (e1.salary) FROM emp
e1 WHERE 3 = (SELECT COUNT (DISTINCT (e2.salary)) FROM emp e2 WHERE
e1.salary<=e2.salary));
Output:
ECODE ENAME SALARY DNO DESG DT_JN
---------- -------------------- ------------ ------- ------- ---------
E09 PINAKI BOSE 5500 D02 PROGRAMMER 26-AUG-94
It is possible for a subquery to return more than one column for each row that it returns. In the
case that a simple subquery returns multiple columns a comparison can be made by creating a
list in comparing the return values of the subquery and the columns to be compared. Below is the
general syntax for a subquery returning multiple columns.
Single row subquery syntax for multiple columns is given below-
SELECT <column_list>
FROM <table_list>
WHERE ( column_name1, …, column_nameK ) = ( SELECT …..);
Query: List the details of the employees getting highest salary in each department
A subquery can return multiple values. In that case relational operator cannot be used for
comparison. Multi-row subqueries require a multivalue comparison operator such as IN. The IN
Subquery tests whether a scalar value matches the single query column value in any subquery
result row. The general form of such a query is as follows.
SELECT <column list>
FROM <table_list>
WHERE <column_name> [NOT] IN (SELECT statement);
Note: The comparison operator can use IN or NOT IN because the inner query can return a list.
Single value comparison operators such as >, <, <=, >= and = are not allowed.
o NON-CORRELATED SUBQUERY
Query: List the departments having more than 2 employees working in that department.
SELECT * FROM dept WHERE dno IN (SELECT dno FROM emp GROUP BY dno
HAVING COUNT(*)>2);
Output:
DNO DNAME CITY
----- ------------------------------ -------------------------
D01 PROJECT KOLKATA
D02 RESEARCH CHENNAI
Query: Retrieve employee details who are not assigned in any project.
o CORRELATED SUBQUERY
DESG
------------------------------
PROGRAMMER
NESTED SUBQUERY
It is possible to nest subqueries but it is not a practice that makes sense beyond three or four
levels deep. The following example demonstrates a nested subquery. Both subqueries are multi-
row subqueries.
Query: Retrieve the code, department number and name of each employee who are
working in the project located in the same city as their departments
7 rows selected.
SELECT <column_list>
FROM <table_list>
WHERE ( <column_name1>, …, <column_nameK> ) IN ( SELECT …..);
7 rows selected.
If we use equality operator(=) instead of IN operator in the third predicate then oracle generates
an error as inner subquery returns multiple rows
SELECT DISTINCT E.ecode, ename, E.dno
FROM emp E, dept D, assigns A
WHERE E.dno=D.dno
AND E.ecode=A.ecode
AND (pid,city) = (SELECT pid, location FROM project)
Output:
AND (pid,city) = (SELECT pid, location FROM project)
*
ERROR at line 5:
ORA-01427: single-row subquery returns more than one row
Syntax:
SELECT <select_list>
WHERE <expression> <relational_operator> [ANY | ALL] (subquery);
➢ ALL
ALL works with a comparison operator and a list. The ALL comparison operator is true whenever
all the values, produced by the subquery, compares favorably with the column being compared.
>ALL means greater than all the values these return from the subquery i.e., greater than the
largest value among the values returns from the inner query.
Query: Find the employee getting the salary more than every employee of the ‘PROJECT’
department.
Query: Find the details of the employee(s) who is/are getting highest salary.
It is to be noted that if the inner query introduced with ALL and a comparison operator, returns
NULL as one of its values, the entire query fails.
ANY works with a comparison operator and a list. The ANY comparison operator is true
whenever one or more of the list elements compares favorably with the column being compared.
>ANY means that greater than at least one value i.e. greater than the minimum.
>ANY (1, 2, 3) is equivalent to >1
<ANY means that less than the maximum i.e. <ANY(1,2,3) implies <3
=ANY(1,2,3) means =1 OR =2 OR =3
<> ANY (1, 2, 3) means NOT 1 OR NOT 2 OR NOT 3
The following equivalences are listed.
Query: Find the employees getting salary larger than the minimum salary of the
PERSONNEL department.
Query: Find the employees getting same salary as the salary of any employee of the
PERSONNEL department.
Look at the ASSIGN table. The employee with codes ‘E04’ and ‘E05’ are absent in the ASSIGN
table. Obviously their records will be the output. But the following query will give all the rows of
the EMP table.
Because <> ANY (1, 2, 3) means NOT 1 OR NOT 2 OR NOT 3 whereas NOT IN (1, 2, 3) implies
NOT 1 AND NOT 2 AND NOT 3. Therefore the query should be
Whenever a legal subquery fails to produce output, ALL is automatically TRUE but ANY is
automatically FALSE.
Illustration:
Look at the DEPT table there is no department at BANGALORE.
The keywords EXISTS and NOT EXISTS are designed for use only with subqueries. They are
equivalent to the existential quantifier (and its negated form) that is seen in tuple calculus. Both
versions return either true or false only. EXISTS keyword is a WHERE clause tests for existence
or non existence of data that meets the criteria of the subquery. Existence or non existence
implies presence or absence of the “empty set” of rows. If the subquery returns at least one row,
the subquery evaluates TRUE. The EXISTS operator is used with correlated subqueries. It has
the following general format-
SELECT <select_list>
WHERE [NOT] EXISTS (subquery);
It should be noted that Any valid EXISTS subquery must contain an outer reference (the
subquery where clause references a column in the outer query). It must be a correlated subquery.
Query: Find the names of the employees who work in the RESEARCH department.
SELECT DISTINCT ename FROM emp
WHERE EXISTS
(SELECT * FROM dept
WHERE dept.dno = emp.dno AND dname = ‘RESEARCH’);
Output:
ENAME
------------------------------
HARI NANDAN TUNGA
JISHNU BANERJEE
PINAKI BOSE
Query: Which designations are common to more than one department?
SELECT DISTINCT desg FROM emp A
WHERE EXISTS( SELECT * FROM emp B
WHERE A.desg=B.desg
AND A.dno<>B.dno);
Output:
DESG
----------------------------
PROGRAMMER
Query: Retrieve employee details who are not assigned in any project.
SELECT *
FROM emp
WHERE NOT EXISTS
(SELECT *
FROM emp e2
WHERE e2.salary > emp.salary);
Output:
SCALAR SUBQUERIES
A Scalar Subquery can appear as a scalar value in the select list and where predicate of another
query.
For scalar subquery,
• the subquery must reference just one column in the select list.
• it must also retrieve no more than one row. If the subquery retrieves more than one row, it
generates a run-time error and aborts query execution.
Query: List the code, name of the employees along with the corresponding city of the
department in which they are working
9 rows selected.
When the subquery returns no rows, a database null is used as the result of the subquery.
e.g.
Query: Find the employees of the department located at BANGALORE.
9 rows selected.
SELECT * FROM emp WHERE ’PERSONNEL’= (SELECT dname FROM dept WHERE
emp.dno=dept.dno);
Output:
ECODE ENAME SALARY DNO DESG DT_JN
---------- -------------------- ------------ ------- ------- ---------
E04 JAYANTA GANGULY 6000 D03 ACCOUNTANT 12-SEP-96
E05 RAJIB HALDER 4000 D03 CLERK 07-OCT-95
If the scalar subquery returns multiple rows then oracle generates an error. For example, to list
the code, name of the employees along with the corresponding project id which they are
assigned.
TABLE SUBQUERIES
Table Subqueries are queries used in the FROM clause, replacing a table name. Basically, the
result set of the Table Subquery acts like a base table in the FROM list. Table Subqueries can
Query: List the details of the employees along with the corresponding location (city) of the
RESEARCH department.
SELECT E.*,city
FROM emp E, dept D WHERE E.dno=D.dno AND dname='RESEARCH';
SELECT E.*,city
FROM emp E, (SELECT dno, city From dept WHERE dname='RESEARCH') D
WHERE E.dno=D.dno;
Output:
SELECT * FROM (SELECT ecode, ename, salary, ROWNUM RN FROM emp WHERE
ROWNUM < 6) WHERE RN = 5;
Output:
ECODE ENAME SALARY RN
----- ------------------------------ ---------- ----------
E05 RAJIB HALDER 4000 5
It is to be noted that the 9 is just one greater than the maximum row of the required rows (means
x= 5, y=8, so the inner values is y+1).
Query: Retrieve only rows 5 to 8 from EMP table and also display the department name
corresponding to each department number of the selected employees.
For example,
The ‘dept02’ table has three columns ecode, ename and salary. The type and size of these
columns are same as the ‘emp’ table.
DESC dept02
Output:
To create an empty copy of an existing table, the following SQL statement has to be entered.
Query: Increase the salary of the employees working in the RESEARCH department by 5%.
UPDATE emp
SET salary=salary*1.05
WHERE dno=(SELECT dno FROM dept WHERE dname=’RESEARCH’);
Output:
3 rows updated.
9 rows selected.
Subquery can be used in SET clause of the UPDATE statement. The syntax is given below.
Query: Increase the salary of the employees of the dept ‘D03’ by 2% of the highest salary
drawn by the employee of ‘D01’ department;
Output:
2 rows updated.
9 rows selected.
It should be noted that the subquery should return a single value. Otherwise an error message
will be displayed. If the query is written in which multiple values are returned from the subquery,
then the UPDATE command fails. Notice the following query.
UPDATE emp
SET salary = salary + 0.02*(SELECT salary FROM emp
WHERE dno=’D01’) WHERE dno=’D03’;
Output:
Query: Increase the salary of all employees by 2% of the highest salary drawn by the
employee of their respective department;
UPDATE emp A
SET salary = salary + 0.02*(SELECT MAX(salary) FROM emp B WHERE
A.dno=B.dno);
9 rows selected.
Multiple columns can be specified with SET clause along with subquery. The subquery should
return single value from each multiple columns.
Query: Transfer the employee with code ‘E02’ to department ‘D02’ as one of the highest
paid salaried employee of that department.
UPDATE emp
SET (dno,salary) = (SELECT dno,MAX(salary) FROM emp
WHERE dno =’D02’ GROUP BY dno) WHERE ecode = ‘E02’;
Output:
1 row updated.
10 rows selected.
Like UPDATE command, subquery can be used with DELETE command also.
Consider the EMP table with original data.
6 rows selected.
Query - Delete all employees who make more than the average salary:
It is to be noted that the average would change while deletion of each row was occurring.
But this was not occurred as SQL do the following:
1. Evaluate the where clause for each tuple of the relation being deleted from. No tuples are
deleted in this step, but the result of evaluating the where clause is stored for each tuple.
2. After the where clause is evaluated for each tuple, all tuples that satisfied the WHERE
clause are deleted.
That is, SQL marks tuples for deletion first, and then deletes all tuples. This guarantees that the
where clause is always evaluated over the value of the relation before any deletions occur.