SQL Exercise 9

JOINS AND SUBQUERIES

In our previous examples we queried only one table at a time. Typically data stored in the database will be in more than one table. What then? The join and subquery features give you the ability to query multiple tables. Keep in mind the more tables involved in a SELECT statement, the more complex the SQL.

JOINING TABLES

The function of combining data from multiple tables is called joining. A join will match the data from two or more tables based on the values in columns you specify. All matches are combined, creating a resulting row, which is the concatenation of the columns from each table.

Looking at the EMPLOYEE table we can see that we have a column called DEPTNO. Suppose we had a table called DEPT, which carried attributes such as department number, department name, location of the department, manager number of the department and columns for budget figures such as expenses and revenue.

Here is the data stored in that table:

SQL> SELECT * FROM DEPT;

 

DEPTNO

DEPTNAME

LOC

MGR

EXP_BUDG

REV_BUDG

10

Accounting

Dallas

200

100000

0

30

Research

San Francisco

105

125000

0

40

Sales

Boston

109

280000

800000

50

Manufacturing

Houston

210

130000

0

60

Shipping

Houston

215

90000

0

 

Now suppose we needed to know the office location for the employee named 'Chen'.

In reviewing the DEPT table above we note that department 10 is in 'Dallas' but the table does not include the employee name field.

By reviewing the EMPLOYEE table below we can see that 'Chen' works in department 10 but the location of that department is not contained within this table.

 

EMPNO

NAME

JOB

SALARY

COMM

DEPTNO

S

100

Wilson

Clrk

1700

 

10

M

101

Smith

Slsm

2500

1300

40

F

103

Reed

Anlt

3500

 

30

M

105

Watson

Mngr

4500

0

30

M

109

Allen

Mngr

3800

8000

40

F

110

Turner

Clrk

1800

 

50

M

200

Chen

Mngr

2900

 

10

F

210

Ramirez

Mngr

3650

 

50

M

213

McDonnel

Clrk

1625

 

60

M

214

Simpson

Drvr

825

 

60

M

215

Di Salvo

Spvr

2700

 

60

M

220

Schwartz

Slsm

4250

5300

40

F

 

How do we get this information without doing two separate SELECT statements?

Since both the EMPLOYEE table and the DEPT table carry the column DEPTNO we can join the tables on that column and relate rows from the DEPT table with rows in the EMPLOYEE table. In doing this we are creating a virtual table which contains all the attributes for rows from the department table and the employee table where the DEPTNO is equal. This virtual table contains the following attributes: DEPTNO, DEPTNAME, LOC, MGR, EXP_BUDG, REV_BUDG, EMPNO, NAME, JOB, SALARY, COMM, and SEX.

In ORACLE we are able to join a multitude of tables together in this fashion. Although it may not be practical it is possible. Be aware that the more tables we join the more complicated the SQL becomes.

In order to find the location of the employee named Chen, we would use the following query.

SQL> SELECT NAME, LOC

FROM EMPLOYEE, DEPT

WHERE NAME = 'Chen'

AND EMPLOYEE.DEPTNO = DEPT.DEPTNO; ç join condition

 

NAME

LOC

Chen

Dallas

 

The results table consists of one row that meets the specifications of the where clause. Since we selected only name and location, only those columns were returned. However, we can retrieve as many attributes from each table as we need.

Let's join all the rows of the EMPLOYEE table with the DEPT table selecting department number, department name, employee number, employee name, job, sex and salary and order the rows by employee number within department number. The query to retrieve this information is written below.

 SQL> SELECT EMPLOYEE.DEPTNO, DEPTNAME, EMPNO, NAME, JOB, SEX,

SALARY

FROM EMPLOYEE, DEPT

WHERE EMPLOYEE.DEPTNO = DEPT.DEPTNO ç join on DEPTNO

ORDER BY EMPLOYEE.DEPTNO, EMPNO;

The results table should look like this.

DEPTNO

DEPTNAME

EMPNO

NAME

JOB

S

SALARY

10

Accounting

100

Wilson

Clrk

M

1700

10

Accounting

200

Chen

Mngr

F

2900

30

Research

103

Reed

Anlt

M

3500

30

Research

105

Watson

Mngr

M

4500

40

Sales

101

Smith

Slsm

F

2500

40

Sales

109

Allen

Mngr

F

3800

40

Sales

220

Schwartz

Slsm

F

4250

50

Manufacturing

110

Turner

Clrk

M

1800

50

Manufacturing

210

Ramirez

Mngr

M

3650

60

Shipping

213

McDonnel

Clrk

M

1625

60

Shipping

214

Simpson

Drvr

M

825

60

Shipping

215

Di Salvo

Spvr

M

2700

 

Note something unusual about this query? Since we wanted to list DEPTNO as part of the output and this attribute resides within each table, we had to tell ORACLE which table (it doesn't matter which one) we wanted to use to extract DEPTNO. When you have an attribute which resides in more than one table if you do not specify the table in the SELECT statement you will get an ambiguity error.

To cut down on the amount of typing required in your queries you can use aliases in the SELECT and WHERE clauses. For example, if you wanted to use the abbreviation 'E' for the EMPLOYEE table in your query all you need do is tell ORACLE that EMPLOYEE will be reference by E in the FROM clause. The following query would result in the same output:

SQL> SELECT E.DEPTNO, DEPTNAME, EMPNO, NAME, JOB, SEX, SALARY

FROM EMPLOYEE E, DEPT ç alias table

WHERE E.DEPTNO = DEPT.DEPTNO ç join on DEPTNO

ORDER BY E.DEPTNO, EMPNO;

  

SUBQUERIES

With SQL we are able to nest SELECT statements together in what are called subqueries. Using a subquery allows you to search the results table from another SELECT statement.

Going back to our previous example of retrieving the office location for Chen we could have used a subquery to obtain the same information.

 SQL> SELECT LOC ç main select query

FROM DEPT

WHERE DEPTNO IN

(SELECT DEPTNO ç subquery

FROM EMPLOYEE

WHERE NAME = 'Chen');

 

LOC

--------------- ç results table

Dallas

  

ORACLE processes this statement by first finding the department number for all the rows where the name is equal to 'Chen' and stores it in a virtual table which contains one column (DEPTNO). ORACLE then processes the next SELECT statement 'SELECT LOC FROM DEPT WHERE DEPTNO IN' by matching department numbers in the DEPT table to department numbers returned from the first SELECT statement. Whenever these are equal, the location is returned to the results table.

Suppose we want to find the employee name, employee number and department number for all employees who work in Houston, with the results in descending employee number order. One way to write this query is show below.

SQL> SELECT NAME, EMPNO, DEPTNO ç main select

FROM EMPLOYEE

WHERE DEPTNO IN

(SELECT DEPTNO ç subquery

FROM DEPT

WHERE LOC = 'Houston')

ORDER BY EMPNO DESC;

The results table will look like this.

NAME

EMPNO

DEPTNO

Di Salvo

215

60

Simpson

214

60

McDonnel

213

60

Ramirez

210

50

Turner

110

50

 

The above query could have been formatted using the EXISTS operator. The EXISTS and NOT EXISTS operators return a value of true or false depending on the subquery that follows it. If the query returns at least one row which satisfies the conditions specified then the value of the query is true. The lack of any rows satisfying the specified conditions means the value of the operator is false. For example:

SQL> SELECT NAME, EMPNO, DEPTNO

FROM EMPLOYEE

WHERE EXISTS ç EXISTS operator

(SELECT *

FROM DEPT

WHERE LOC = 'Houston'

AND EMPLOYEE.DEPTNO = DEPT.DEPTNO)

ORDER BY EMPNO DESC;

 The results table is identical to the one received from the previous query.

 

Subqueries may also be used when working with data from a single table. For example using the EMPLOYEE table, suppose we want to retrieve the names and salaries for all employees who earn more than the average salary.

Using the group function AVG the SQL implementation is as follows:

SQL> SELECT NAME, SALARY ç main select

FROM EMPLOYEE

WHERE SALARY >

(SELECT AVG(SALARY) ç subquery

FROM EMPLOYEE);

 The results table will look like this.

NAME

SALARY

Reed

3500

Watson

4500

Allen

3800

Chen

2900

Ramirez

3650

Schwartz

4250

 

Recall that in our lesson on Group Functions,  we noted that column names may not be used with group functions in SELECT statements. For example, in order to find the name of the employee who earns the least salary, a subquery is needed. The query to retrieve this data is shown below.

SQL> SELECT NAME, SALARY

FROM EMPLOYEE

WHERE SALARY =

(SELECT MIN(SALARY)

FROM EMPLOYEE);

The results table from this query is shown below.

NAME

SALARY

Simpson

825

 

NOTE: Many subquery statements can be converted to equivalent join statements unless they contain EXISTS or NOT EXISTS. Equivalently, many joins can be rewritten as subqueries.

ORACLE contains an extensive set of SQL commands. It is not the intention of this tutorial to cover all of these commands. Consult a book on ORACLE for further information.

For you to try:

  1. Suppose you need to know the name, job, department name, and location of all female employees. Write a SQL query that will return this information. Order the list in alphabetical order by employee name.
  2. Suppose you need to know the name, department name, and employee number of all managers. Write a SQL query that will retrieve this information. Order the list in alphabetical order by department name.
  3. Suppose you need to know the name and department name of the employee who earns the highest salary. Write a SQL query to return this information.
  4. Suppose you need to know the name, department name, and commission of all employees who were paid commission. Write a SQL query to retrieve this information. Order the list in alphabetical order by employee name.
  5. Suppose you need to know the employee name and department name of all employees that work in a department that has at least 3 employees. Write a SQL query to retrieve this information. Order the list in alphabetical order first by department name, then by employee name.

 

Go here to check your answers.


Return to ORACLE/SQL Tutorial Contents Page | Return to Exercise 8 | Go to Next Lesson