0% found this document useful (0 votes)
6 views

chp04 05 More SQL

Chapter 4. Intermediate SQL Chapter 5. Advanced SQL

Uploaded by

thisisskimps
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views

chp04 05 More SQL

Chapter 4. Intermediate SQL Chapter 5. Advanced SQL

Uploaded by

thisisskimps
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 23

Chapter 4.

Intermediate SQL

Contents
Chapter 4. Intermediate SQL 1
Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Grouping and summarising information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
A very common error with GROUP BY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
The HAVING clause . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Writing queries on more than one table - Joins . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Avoiding ambiguously named columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Outer JOINs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Using table aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
SELF JOINS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Additional note on joins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Nested queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
The depth and breadth of nested queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
The UNION operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
The INTERSECT operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
The MINUS operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
ANY or ALL operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Correlated sub-queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Additional features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

Chapter 4. Intermediate SQL

Objectives
At the end of this chapter you should be able to:

• Group and summarise data together.

• Combine the grouping mechanisms with the aggregation functions.

• Write queries that retrieve information from a number of tables.

• Combine the results of multiple queries in various ways.

Introduction
This chapter examines queries on more than one table, summarising data, and combining the results of multiple
queries in various ways.

Context
This chapter forms the bridge between the chapter in which the SQL language was introduced, and the coverage of
the data definition language (DDL) and data control language (DCL) provided in the next chapter called Advanced
SQL.

1
Grouping and summarising information
Information retrieved from an SQL query can be placed into separate groups or categories with the GROUP BY
clause. GROUP BY is optional. If it appears in the query, it comes after any WHERE clause and before any ORDER
BY.

Example: count the number of employees in each department

To answer this question, it is necessary to place employees in the EMP table into separate categories, one for
each department. This can be done as follows:

SELECT ... FROM EMP GROUP BY DEPTNO


To complete the query and obtain the result in figure 1, we include on the select-list the DEPTNO column, so
that we can see what we are grouping by, and the COUNT function:

SELECT DEPTNO,COUNT(EMPNO) FROM EMP GROUP BY DEPTNO;

Figure 1: Result of SELECT DEPTNO,COUNT(EMPNO) FROM EMP GROUP BY DEPTNO

The query is run in two steps. The first step groups all employees by DEPTNO. The second step counts the number
of employees in each group. Note that GROUP BY, like ORDER BY, can include more than one data item, so for
example if we specify:

GROUP BY DEPTNO, JOB

the results will be returned initially categorised within departments, and then within that, categorised into
employees who do the same job.

Aside: A note on the COUNT function:

We have specified between the parentheses of the COUNT function above that we are counting EMPNOs. Suppose we
wanted to count the number of JOBs instead.

• If we specified this as COUNT(JOBNO) we would get the number of non-null values in the JOB column for each
department.
• If we specified this as COUNT(*) we would get the number of rows in the table for each department
(irrespective of JOBNO content).
• If we specified this as COUNT(DISTINCT JOBNO) we would get the number of distinct non-null values in the
JOB column for each department.

A very common error with GROUP BY

All column names in the select-list must either appear in the GROUP BY clause or be inside the brackets of an
aggregate function. Many people when first using the GROUP BY clause, fall into the trap of asking for a
data item at the individual employee level, such as SAL. It is fine to display average salaries, as these are
averaged across the group, and are therefore meaningful at the group level. However, if we had asked to display
individual salaries, we would have had the error message “not a group by expression”, referring to the fact that
SAL is an individual attribute of an employee, and not an attribute of the group. The only individual level
items you can include in the select-list, are items which are shared by a every row in the group; and these are
exactly the items you are grouping by. Hence it should be clear why we summarise this as an easy way to check
yourself: All column names in the select-list must either appear in the GROUP BY clause or be inside the brackets
of an aggregate function.

2
The HAVING clause

The HAVING clause filters out specific groups, exactly in the same way that the WHERE clause filters out
individual rows. The HAVING clause always follows a GROUP BY clause, and is used to test properties of the
grouped information. For example, if we are grouping information at the department level, we might use a HAVING
clause to exclude departments with less than a certain number of employees. This could be coded as below,
obtaining the result in figure 2:

SELECT DEPTNO,COUNT(EMPNO) FROM EMP GROUP BY DEPTNO HAVING COUNT(EMPNO) > 4;

Figure 2: Result of SELECT DEPTNO,COUNT(EMPNO) FROM EMP GROUP BY DEPTNO HAVING COUNT(EMPNO) > 4

Department number 10 has four employees in our sample data set, and has been excluded from the results because
of the HAVING clause. The properties that are tested in a HAVING clause must be properties of groups, not of
individual rows. So, like those in the select-list, one must either test against values of a grouped-by item,
such as,

HAVING JOB = ‘SALESMAN’ OR JOB = ‘ANALYST’

or test against some aggregate property of the group, e.g. the number of members in the group (as in the example),
or tests on average salary of a group, etc. The HAVING clause, when required, always follows immediately after
the GROUP BY clause to which it refers. It can contain compound conditions, linked by AND or OR (as above), and
parentheses may be used to nest conditions.

Writing queries on more than one table - Joins


We may wish to display employee numbers and names, alongside the name of the department in which employees
work. To do this, we will need to combine information from both tables, as the employee details are stored
in the EMP table, while the department name information is stored in the DEPT table (in the DNAME attribute).
Firstly, this requires listing both the EMP and DEPT tables in the table-list: the table-list contains all
tables required to be accessed during the execution of a query. So our FROM clause will read:

FROM EMP, DEPT

The order in which the tables are listed in the table-list does not affect the result. Listing both the EMP
and the DEPT tables after the FROM keyword is not sufficient. We want to relate the display of a department
name with the display of numbers and names of employees who work in that department. So we require the query to
relate employee rows in the EMP table with their corresponding department rows in the DEPT table. This is done
is using a relational join:

WHERE EMP.DEPTNO = DEPT.DEPTNO

What this is expressing is that we wish rows in the EMP table to be related to rows in the DEPT table, by
matching rows from the two tables whose department numbers (DEPTNOs) are equal. We are using the DEPTNO column
from each employee row in the EMP table, to link that employee row with the department row for that employee
in the DEPT table.

The full query would therefore be:

SELECT EMPNO,ENAME,DNAME FROM EMP,DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO;


Note EMP.DEPTNO and DEPT.DEPTNO are used to perform the join, but we do not wish to display any DEPTNO information,
so it is not included in the select-list. This gives the results for our test data set as depicted in figure 3.

Example joining two tables

3
Figure 3: Result of SELECT EMPNO,ENAME,DNAME FROM EMP,DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO

4
Suppose we want to list the names and jobs of employees, together with the locations in which they work. LOC
is stored in the DEPT table, and so requires a join, in order to display employee information along with the
locations of the departments in which they work, as shown in figure4. The SQL standard provides the following
alternative ways to specify this join:

1. SELECT ENAME,JOB,LOC FROM EMP,DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO;

2. SELECT ENAME,JOB,LOC FROM EMP JOIN DEPT ON EMP.DEPTNO = DEPT.DEPTNO;

3. SELECT ENAME,JOB,LOC FROM EMP JOIN DEPT USING DEPTNO;

4. SELECT ENAME,JOB,LOC FROM EMP NATURAL JOIN DEPT;


The <table1> JOIN <table2> ON operator can be used instead of a WHERE clause. If followed by USING <column-
list> this means that each attribute in <column-list> occurs in both tables and the join must match rows on
equal values of these attributes. If NATURAL JOIN is used instead of JOIN, the effect is the same as USING
<all-column-names-that-appear-in-both-tables>.

Figure 4: Example joining two tables

Avoiding ambiguously named columns

DEPTNO has been used as the data item to link rows in the EMP and DEPT tables. In the DEPT table, DEPTNO acts
as the primary key, while in the EMP table, DEPTNO acts as a foreign key, linking each EMP row with the row
in the DEPT table for the department to which the employee row belongs. If we wish to refer to DEPTNO in the
select-list, we would need to specify which instance of DEPTNO we are referring to: the one in the EMP table,
or the one in the DEPT table. We simply prefix DEPTNO with the table name, placing a full stop (.) character
between the table name and column name: for example, EMP.DEPTNO, or DEPT.DEPTNO. In this way, the system can
identify which instance of DEPTNO is being referenced.

5
Outer JOINs

Supposing, for example, we wish to list all departments with the employee numbers and names of their employees,
plus any departments that do not contain employees.

The basic form of the JOIN only extracts matching instances of rows from the joined tables. To also obtain row
instances that do not match a row in the other table, we use an OUTER JOIN. There are 3 types of OUTER JOIN:
LEFT, RIGHT, and FULL OUTER JOINS. To demonstrate OUTER JOINs, we use the following tables.

Person table

The person table holds the information of people (see figure 5). The ID is the primary key. A person can own a
car or not.

Figure 5: The Person relation

Car table

The car table holds information on cars and REG is its primary key (see figure 6). A car may or may not have
an owner.

Figure 6: The Car relation

LEFT OUTER JOIN

Example: List all persons together with their car’s registration and model, including any person without any
car:

SELECT ID,NAME,REG,MODEL FROM Person LEFT JOIN car ON Person.ID = Car.OWNER;


The query returns all the persons with cars, plus the one instance of a person (ID 704555) having no car, as
shown in figure7. The LEFT JOIN is used because we want all rows from the table on the left of the word JOIN
to be included.

Figure 7: Result of the LEFT JOIN example

RIGHT OUTER JOIN

Example: List all cars together with their owner’s identification and name, including cars not owned by anyone.

SELECT REG,MODEL,ID,NAME FROM Person RIGHT JOIN car ON Person.ID = Car.OWNER;


The query returns all the cars that are owned, plus the one instance of a car not owned by anyone, as shown in
figure8. For a RIGHT JOIN, all rows of the table on the right of the word JOIN are included.

6
Figure 8: Result of the RIGHT JOIN example

FULL OUTER JOIN

If you wish to show both rows of those persons that don’t own any car, and rows of cars that don’t have any
owner (see figure 9), then you need to use the FULL OUTER JOIN:

SELECT REG,MODEL,ID,NAME FROM Person FULL JOIN car ON Person.ID = Car.OWNER;

Figure 9: Result of the FULL JOIN example

Using table aliases

Aliases, or alternative names, can be specified in the table-list. For example, the above FULL OUTER JOIN query
can be written using aliases:

SELECT REG,MODEL,ID,NAME FROM Person p FULL JOIN car c ON p.ID = c.OWNER;

SELF JOINS

Sometimes it is necessary to JOIN a table to itself in order to compare rows from the same table. An example
of this might be if we wish to compare values of salary on an individual basis between employees.

Example: find all employees who are paid more than “JONES”

What is required here is to compare the salaries of employees with the salary paid to JONES. One way of doing
this involves JOINing the EMP table with itself, so that we can carry out salary comparisons in the WHERE clause
of an SQL query. However, if we wish to JOIN a table to itself, we need a mechanism for referring to the
different rows being compared. In order to specify the query to find out which employees are paid more than
JONES, we shall use two table aliases, E and J for the EMP table. We shall use E to denote employees we are
comparing with JONES, and J to denote JONES’ row. This leads to the following query:

SELECT E.EMPNO,E.ENAME,E.SAL,J.EMPNO,J.ENAME,J.SAL FROM EMP E,EMP J


WHERE E.SAL > J.SAL AND J.ENAME = 'JONES'

Figure 10: Employees who are paid more than JONES

7
The result can be see in figure 10. We ensure that the alias J is associated with the employee JONES through
the second condition in the WHERE clause: AND J.ENAME = ‘JONES’.

Additional note on joins

We have seen that JOINing two tables together involves one JOIN condition. In general, JOINing N tables together
requires the specification of N-1 JOIN conditions. A lot of work has gone into the development of efficient
algorithms for the execution of JOINs. In spite of this, JOINs are still an expensive operation.

Nested queries
In SQL we can include one query within another. This is known as nesting queries, or writing sub-queries.
Example: Find all employees who are paid more than JONES. This can be seen as a two-stage task:

1. Find Jones’ salary.

2. Find all those employees who are paid more than the salary found in step 1.

We might code step 1 as follows:

SELECT SAL FROM EMP WHERE ENAME = 'JONES'


The nested query mechanism allows us to enclose this query within another one, which we might use to perform
step 2:

SELECT EMPNO,ENAME,SAL FROM EMP WHERE SAL > ...


We simply need the syntax to enclose the query to implement step 1 in such a way that is provides its result to
the query which implements step 2. This is done by enclosing the query for step 1 in parentheses, and linking
it to the query for step 2 as follows:

SELECT EMPNO,ENAME,SAL FROM EMP WHERE SAL > (SELECT SAL FROM EMP WHERE ENAME = 'JONES');
This gives the results in figure 11.

Figure 11: Result of the nested select example

These are indeed the employees who earn more than JONES (who earns 2975). Whenever a query appears to fall
into a succession of natural steps such as the one above, it can be easier to code it as a nested query. Just
bear in mind that some nested queries return one value, others return a set of values. Suppose we want to
find employees who earn the same salary as employee 7566 (Jones). As the inner query returns just one value,
employee 7566’s salary, we use the equal sign, e.g.

SELECT ENAME FROM EMP


WHERE SAL = (SELECT SAL FROM EMP WHERE EMPNO = 7566)
If, however, the inner query might return more than one row, we must use the keyword IN, so that we can check
the set of values returned by the inner query. Example: Find the names of departments that have a manager:

SELECT DNAME FROM EMP


WHERE DEPTNO IN (SELECT DEPTNO FROM EMP WHERE JOB = 'MANAGER' )

8
The depth and breadth of nested queries

There is no practical limit to the number of queries that can be nested. And many queries can be included at
the same level of nesting, using AND / OR :

SELECT ... FROM ...


WHERE CONDITION 1 (SELECT ... FROM ... WHERE ...)
AND/OR CONDITION 2 (SELECT ... FROM ... WHERE ...)
AND/OR ...

The UNION operator


Suppose employee WARD is in a table called EMP1, and employee SCOTT in table EMP2. To find details of employees
receiving the same salaries as either SCOTT or WARD:

SELECT EMPNO,ENAME,SAL FROM EMP WHERE SAL IN


(SELECT SAL FROM EMP1 WHERE ENAME = 'WARD'
UNION
SELECT SAL FROM EMP2 WHERE ENAME = 'SCOTT');
The SQL UNION operator can only be applied to sets that are union compatible, i.e. that have the exact same
columns. In our example, each set in the example has only one column, SAL, so they are indeed union compatible.

The INTERSECT operator


INTERSECT can be used to extract the rows in common between two sets of query results:

SELECT * FROM EMP1


INTERSECT
SELECT * FROM EMP2;
Here the INTERSECT operator is used to find rows that exist in both table EMP1 and table EMP2. Again, sets
compared with one another using the INTERSECT operator must be union compatible, so this query will only work
if EMP1 and EMP2 have the exact same columns.

The MINUS operator


Example:

SELECT EMPNO,ENAME,SAL FROM EMP WHERE EMPNO IN


(SELECT EMPNO FROM EMP1
MINUS
SELECT EMPNO FROM EMP2);
The result lists the details for employees who appear in table EMP1 but not in table EMP2. MINUS must be applied
to sets that are union compatible, as is the case in our example.

ANY or ALL operator


The ANY or ALL operators may be used for sub-queries that return more than one row. ANY compares a value to
each value returned by a sub-query, and returns TRUE if any one of them meets the condition in the WHERE clause.
To display employees who earn more than the lowest salary in Department 30 (see figure 12), enter:

SELECT ENAME, SAL, JOB, DEPTNO FROM EMP


WHERE SAL > ANY (SELECT SAL FROM EMP WHERE DEPTNO = 30)
ORDER BY SAL DESC;
ALL compares a value to every value returned by a sub-query, and returns TRUE only if every one of them meets
the condition in the WHERE clause. The following query finds employees who earn more than every employee in
Department 30 (see figure ??):

SELECT ENAME, SAL, JOB, DEPTNO FROM EMP


WHERE SAL > ALL (SELECT SAL FROM EMP WHERE DEPTNO = 30)
ORDER BY SAL DESC;

9
Figure 12: Result of the example using ANY

Result of the example using ALL

10
The inner query retrieves the salaries for Department 30. The outer query, using the All keyword, ensures that
the salaries retrieved are higher than all of those in department 30. Note that the NOT operator can be used
with IN, ANY or ALL.

Correlated sub-queries
A correlated sub-query is a nested sub-query that is executed once for each ‘candidate row’ considered by the
main query, and thus uses a value from a column in the outer query. This causes the correlated sub-query to
be processed in a different way from the ordinary nested sub-query. With a normal nested sub-query, the inner
select runs first and it executes once, returning values to be used by the main query. A correlated sub-query,
on the other hand, executes once for each candidate row to be considered by the outer query. The inner query
is driven by the outer query. Steps that the DBMS takes when running a correlated sub-query are:

1. The outer query fetches a candidate row.

2. The inner query is executed, using the value from the candidate row fetched by the outer query.

3. Whether the candidate row is retained depends on the values returned by the execution of the inner query.

4. Steps 1 to 3 are repeated until no candidate row remains in the outer query.

Example

We can use a correlated sub-query to find employees who earn a salary greater than the average salary for their
department:

SELECT EMPNO,ENAME,SAL,DEPTNO FROM EMP E


WHERE SAL > (SELECT AVG(SAL) FROM EMP WHERE DEPTNO = E.DEPTNO)
ORDER BY DEPTNO;
This produes the result in figure 13.

Figure 13: Result of the correlated subquery example

This is a correlated sub-query since we have used a column from the outer select, namely E.DEPTNO, in the WHERE
clause of the inner select.

Additional features
Note that newer and more advanced features that can be used with SELECT, such as CASE and IF operators, are not
examinable in this module. Having mastered this chapter and knowing that they exist however, you are well placed
to use them, should you in practice later encounter a situation where they are the only possible solution.

Review Questions

1. Give a SQL statement to find all employees located in Dallas.

2. Give a SQL statement to list any departments that do not contain any employees.

11
3. Give a SQL statement to fine Which workers earn more than their managers (hint: remember that the MGR
attribute stores the EMPNO of an employee’s manager)?

4. Give a SQL statement to list the total monthly pay, and the total number of employees, for each department.

5. Give a SQL statement to find all jobs with more than two employees.

6. Give a SQL statement to list the details of the highest-paid employee.

7. Give a SQL statement to find whether anyone in department 30 has the same job as JONES.

12
Chapter 5. Advanced SQL

Contents
Chapter 5. Advanced SQL 1
Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Creating tables in SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Copying data by combining CREATE TABLE and SELECT . . . . . . . . . . . . . . . . . . . . . . . . 3
Copying table structures without data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
The ALTER TABLE statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Using ALTER TABLE to add columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Modifying columns with ALTER TABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Removing tables using the DROP TABLE statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Using DROP TABLE when creating tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Adding new rows to table with INSERT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Changing column values with UPDATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Removing rows with DELETE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Creating views in SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Views and updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Renaming tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Creating and deleting a database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Using SQL scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

Chapter 5. Advanced SQL

Objectives
At the end of this chapter you should be able to:

• Create, alter and drop tables in SQL.

• Insert, update and delete rows from SQL tables.

• Create, alter and remove views based on SQL tables, and describe some of the strengths and limitations of
views.

Introduction
This chapter introduces the means by which rows and entire tables are created, changed and removed in SQL. The
important concept of views is also covered.

Creating tables in SQL


Data definition language (DDL) statements are used for creating, modifying and removing data objects. They
affect both physical and logical data structures. The CREATE statement in SQL can be used to bring into being
a range of different data objects, including the following:

• Data tables

• Views on existing tables

1
• Indexes (data structures which speed up access to data)

• Database user accounts

In this section we shall concentrate on the CREATE TABLE statement:

CREATE TABLE <table-name> ( <column-specification-1>, … <column-specification-N>);

Where column specification includes:

• A column name

• The data type of the column

• Where appropriate, a specification of the length of the column

• An optional indicator of whether or not the column can contain null values

Data types

We shall focus on four specific data types found in almost any database environment.

1. VARCHAR: is used to store variable-length character strings.

VARCHAR (<length>)

where length is the maximum length of the character string to be stored.

2. NUMBER: This offers the greatest flexibility for storing numeric data. It accepts positive and negative
integers and real numbers, and has from 1 to 38 digits of precision. The syntax is:

NUMBER (<precision>, <scale>)

where precision is the maximum number of digits to be stored and scale indicates number of digits to the right
of the decimal point. If scale is omitted, then integer (whole) numbers are stored. Note: Some DBMSs, including
MySQL, expect you to use exact data types for numeric data. For example, if you want to hold integers, then
you must use the INT datatype. If you wish to hold decimal numbers, then you must use the DOUBLE datatype.

3. DATE: The format in which dates are represented within attributes of type date is: dd-mon-yyyy; for
example, 10-jan-2000. If an attribute is of type date, simply specify the word DATE after the name of the
attribute in the CREATE TABLE statement.

4. CHAR: is used to store fixed-length character strings.

The final part of a column specification allows us to specify whether or not the column can contain null values,
i.e. whether or not it is a mandatory column. The syntax is simply to specify “Not null” after the data type
specification if nulls are not allowed.

Example CREATE TABLE statements

CREATE TABLE <table-name> ( <column-specification-1>, ..., <column-specification-N>),


PRIMARY KEY (<columnA>, ..., <columnX>),
CONSTRAINT <constraint-name>
FOREIGN KEY (<columnAA>, ..., <columnXX>) REFERENCES <primary-key-specification>)
...............);
Primary and foreign key specifications are not mandatory in a CREATE TABLE statement, but should always be
included to maintain integrity of the database. The DBMS will ensure that a value entered for a foreign key
must either equal a value of the corresponding primary key, or be null. An explanation of the foreign key
specification is as follows:

• The first item is the keyword “CONSTRAINT”, followed by an optional constraint name. Although specifying
a constraint name is optional, it is recommended that you always include it. If you later wish to refer to
the foreign key constraint - e.g. because you wish to remove it - then having a name in the CREATE TABLE
statement will make this much easier.

• The words FOREIGN KEY are followed by a list of the columns to be included in the foreign key, contained
in parentheses and separated by commas.

2
• REFERENCES is a mandatory keyword, indicating that the foreign key will refer to a primary key in another
table.

• The primary key specification starts with the name of the table containing the referenced primary key, and
then lists the columns comprising the primary key, contained in parentheses and separated by commas as
usual.

The full stops (……………) shown in the syntax above indicate that there may be more than one foreign key
specification.

Example

Supposing we have a table which we use to keep track of recording artists. The ARTIST table could be created
with the following statement:

CREATE TABLE ARTIST (


ARTIST_ID NUMBER(2),
ARTIST_NAME VARCHAR2(30),
COUNTRY_OF_ORIGIN VARCHAR2(25),
DATE_OF_BIRTH DATE,
PRIMARY KEY (ARTIST_ID));
To relate a MUSIC_COLLECTION table to the ARTIST table, we use the ARTIST_ID as a foreign key; it will reference
the appropriate artist for each item in the collection:

CREATE TABLE MUSIC_COLLECTION (ITEM_ID NUMBER(4),


TITLE VARCHAR(40),
ARTIST_ID NUMBER(2),
ITEM_TYPE VARCHAR2(1),
DATE_PURCHASED DATE,
PRIMARY KEY (ITEM_ID),
CONSTRAINT FK_ARTIST
FOREIGN KEY (ARTIST_ID) REFERENCES ARTIST (ARTIST_ID));

Copying data by combining CREATE TABLE and SELECT

An extremely useful variant of the CREATE TABLE statement exists for copying data. This uses a SELECT statement
to provide the column specifications for the table to be created and, in addition, the data that is retrieved
by the SELECT statement is copied into the new table structure. The syntax for this form of the statement is
as follows:

CREATE TABLE <table-name> AS <select-statement>;


where <select-statement> can be any valid SQL query.

This form of the CREATE TABLE statement can be used to, for example:

• Copy entire tables.

• Copy subsets of tables using the select-list and WHERE clause to filter the data.

• Create tables which combine data from more than one table (using JOINs).

• Create tables containing aggregated data (using GROUP BY).

Examples of copying data using CREATE TABLE…..SELECT

To create a copy of the EMP table we have used in previous exercises:

CREATE TABLE EMPCOPY AS SELECT * FROM EMP;


To create a table containing a list of employees and their locations we can code:

CREATE TABLE EMPLOC


AS SELECT EMPNO, EMP.DEPTNO, ENAME, LOC FROM EMP, DEPT
WHERE EMP.DEPTNO = DEPT.DEPTNO;

3
To examine the contents of the new table (see figure 1):

SELECT * FROM EMPLOC;

Figure 1: The EMPLOC relation

Copying table structures without data

Sometimes you may wish to copy the structure of a table without moving any of the data. For example:

CREATE TABLE EMPSTRUCT AS SELECT * FROM EMP WHERE 1 = 2;


To verify we have copied the structure, the SQL DESCRIBE is used, and produces the result in figure 2:

DESCRIBE EMPSTRUCT

The ALTER TABLE statement


The ALTER statement can be used to change a number of different types of data objects, including tables, access
privileges and constraints. Here we concentrate on changing the structure of tables. You can use the ALTER TABLE
statement to modify a table’s definition. This statement changes the structure of a table, not its contents.
You can use the ALTER TABLE statement to:

• Add a new column to an existing table.

• Increase or decrease the width of an existing column.

• Change an existing column from mandatory to optional (i.e. specify that it may contain nulls).

Using ALTER TABLE to add columns

Columns can be added to existing tables with this form of the ALTER TABLE statement. The syntax is:

4
Figure 2: The EMPSTRUCT relation

ALTER TABLE <table-name> ADD <column-specification-1>, ............, <column-specification-N>;


For example, to add a budget attribute to the DEPT table, we could specify:

ALTER TABLE DEPT ADD BUDGET NUMBER(4);


We can add a number of columns with one ALTER TABLE statement. The ALTER TABLE statement does not enable the
addition of mandatory fields to tables that already contain data.

Modifying columns with ALTER TABLE

To changed definitions of existing columns, the format is:

ALTER TABLE <table-name> MODIFY <column-specification-1>, ..., <column-specification-N>;


For example, to change our copy of the EMP table, called EMPCOPY, so that the DEPTNO attribute can contain five
digit values:

ALTER TABLE EMPCOPY MODIFY DEPTNO NUMBER(5);


This form of the ALTER TABLE statement can be used to:

• Increase the length of an existing column.

• Transform a column from mandatory to optional (i.e. specify it can contain nulls).

There are a number of restrictions in the use of ALTER TABLE. For example, you cannot:

• Reduce the size of an existing column (even if it has no data in it).

• Change a column from being optional to mandatory.

Removing tables using the DROP TABLE statement


To remove a table, the DDL statement is:

DROP TABLE ;

It is deceptively easy to issue this command, and unlike most systems one encounters today, there is no prompt
about whether you wish to proceed with the process. Dropping a table involves the removal of all the data and
constraints on the table and, finally, removal of the table structure itself. To remove our copy of the EMP
table, called EMPCOPY:

DROP TABLE EMPCOPY;

5
Using DROP TABLE when creating tables

Sometimes, when we wish to recreate an existing table, it will be necessary to drop the table before issuing
the new CREATE TABLE statement. Clearly this should only be done if the data can be lost, or can be safely
copied elsewhere beforehand, perhaps using a CREATE TABLE with a SELECT clause.

Adding new rows to table with INSERT


The INSERT statement is used to add rows to an existing table. The statement has two basic forms:

1. To insert a single row into a table:

INSERT INTO <table-name> (<column-list>) VALUES (<list-of-values-to-insert>);


The <column-list> describes all of the columns into which data is to be inserted. If values are to be
inserted for every column, i.e. an entire row is to be added, then the <column-list> can be omitted. The
<list-of-values-to-insert> comprises the values of the new data row, separated by commas.

To insert a new row into the table DEPTCOPY (this is a copy of the DEPT table):

INSERT INTO DEPTCOPY VALUES (50,'PURCHASING','SAN FRANCISCO');


To insert a new department for which we do not yet know the location:

INSERT INTO DEPTCOPY (DEPTNO,DNAME) VALUES (60,'PRODUCTION');


To insert a number of rows using a SELECT statement, the form of the INSERT statement is: sql INSERT INTO
<table-name> (<column-list>) VALUES <select-statement>; The COLUMN-LIST is optional, and is used to specify
which columns are to be filled when not all the columns in the rows of the target table are to be filled. The
<select-statement> is any valid select statement. This is a powerful way of moving existing data (possibly from
separate tables) into a new table.

Example:

Supposing we created a table MANAGER, which is currently empty. To insert the numbers, names and salaries of
all the employees who are managers into the table we would code:

INSERT INTO MANAGER SELECT EMPNO, ENAME, SAL FROM EMP WHERE JOB = 'MANAGER';
To verify the employees in the table are managers, we can select the data and compare the jobs of those employees
in the original EMP table (the result is shown in figure 3):

SELECT * FROM MANAGER;

Figure 3: Result of the INSERT that selected data from elsewhere in the database

Changing column values with UPDATE


The syntax of the UPDATE statement is as follows:

UPDATE <table-name> SET <assignment-list> WHERE <condition>;


The WHERE clause is used to specify which rows in the target table will be updated. If this WHERE clause is
omitted, all rows in the table will be updated. The SET keyword immediately precedes the column or columns
to be updated, which are specified in the assignment-list. If there is more than one in the list, they are
separated by commas. Each entry in the assignment-list has the format below:

6
<column-name> = <value>

Following the equals sign “=” there are two possibilities for the value to be assigned. An expression can be
used, which may include mathematical operations on table columns as well as constant values. Alternatively,
a SELECT statement can be used to return the value. Examples: For example, to give all the analysts in the
EMPCOPY table a raise of 10%:

UPDATE EMPCOPY SET SAL = SAL * 1.1 WHERE JOB = 'ANALYST';


To set all employees’ MGR fields to that of KING, who is the president of the company:

UPDATE EMPCOPY SET MGR = (SELECT EMPNO FROM EMP WHERE ENAME = 'KING') WHERE ENAME != 'KING';
We included the final WHERE clause to avoid updating KING’s MGR field. Note this example is very poor, as it
is incorrect if other employees are also named King! To verify that the updates have taken place correctly,
obtaining the result in figure 4, we can run:

SELECT EMPNO,ENAME,MGR FROM EMPCOPY;

Figure 4: Result of the UPDATE setting KING as everyone else’s manager

Removing rows with DELETE


The DELETE statement is used to remove single rows or groups of rows from a table:

DELETE FROM <table-name> WHERE <condition>;

If the WHERE clause is omitted, all of the rows will be removed from the table. However, unlike the DROP TABLE
statement, a DELETE statement leaves the table structure in place.

Example 1: To remove all employees named Ford from the EMPCOPY table:

DELETE FROM EMPCOPY WHERE ENAME = 'FORD';

7
Example 2: To remove any employees based in the SALES department:

DELETE FROM EMPCOPY WHERE DEPTNO IN (SELECT DEPTNO FROM DEPT WHERE DNAME = 'SALES');

Creating views in SQL


Views are extremely useful for providing users with a subset of the underlying data tables. Besides increasing
security, views can make querying easier. Views are the means by which users are provided with a tailored schema
of the underlying database. Views are in effect virtual tables, but appear to users as normal base tables.
The difference is that when a view is created, no new table is made and no data is copied or created. A view
definition is simply stored, and used to recreate the view each time it is required. In this sense, views are
equivalent to stored queries. Views are created using the CREATE VIEW statement. The syntax is:

CREATE VIEW <view-name> AS <select statement>;

Example: Create a view showing names and hiredates of employees in the EMP table:

CREATE VIEW EMPHIRE AS SELECT ENAME,HIREDATE FROM EMP WHERE ENAME IS NOT NULL;
To examine the structure of the view EMPHIRE, we can use the DESCRIBE command, just as for table objects,
obtaining the result shown in figure 5:

DESCRIBE EMPHIRE

Figure 5: The result of DESCRIBE EMPHIRE

To see the data in the view, we can issue a SELECT statement just as if the view EMPHIRE is a table. For example,
figure 6 shows the result of running the query below:

SELECT * FROM EMPHIRE;

Views and updates

The data in base tables cannot be updated via a view in the following situations:

• When the view is based on one table, but does not contain the primary key of the table.

• When the view is based on a JOIN.

• When a view is based on a GROUP BY clause or aggregate function, because there is no underlying row in
which to place the update.

• Where rows might migrate in or out of a view as a result of the update being made, e.g. one cannot update
ENAME values in EMPHIRE.

Renaming tables
The syntax of this command is:

RENAME <old-table-name> TO <new-table-name>;


Example: to rename the EMP table to NEWEMP:

RENAME EMP TO NEWEMP;

8
Figure 6: The relation created whenever the EMPHIRE view is accessed

9
The RENAME command is useful when carrying out DDL operations. For example, if we wish to remove a column from
a table and ensure every program using its others columns can continue to use the new copy without any code
changes:

1. Use the CREATE TABLE statement to make a copy of the old table, excluding the column which is no longer
required.

2. Drop the old copy of the table.

3. Rename the new copy of the table to the old (original) name.

The benefit of this approach is

Creating and deleting a database


SQL allows us to create and drop (delete) a database using the following statements respectively:

CREATE SCHEMA <database-name>;

DROP SCHEMA <database-name>;

For example, to create a database called STUDENTS that holds student information, we write the create command
as follows:

CREATE SCHEMA students;


Be careful when using the DROP SCHEMA command. It deletes all the tables created under that database, including
the data. To delete our student database, we write:

DROP SCHEMA students;

Using SQL scripts


SQL statements can be combined into a file and executed as a group. This is useful e.g. to create a set of
tables together. Files containing SQL statements in this way are called SQL script files. Each separate SQL
statement in the file must be terminated with a semi-colon. Having created one or more tables, if you then
decide you wish to make changes to them, the simplest approach is to drop the tables and issue a new CREATE
TABLE statement which implements the required changes. If the tables contained any data you wish to retain, you
should first use CREATE TABLE to copy the data to another table, from which it can be copied back when you have
carried out the required table restructuring. The restructuring of a number of tables is best implemented by
including the required CREATE TABLE statements in a script file. To avoid errors when this file is re-run, it
is customary to place a series of DROP TABLE statements at the beginning of the file, one for each table that
is to be created. In this way you can re-run the script file as often as necessary, with no problems. The first
time it runs, assuming the tables have not already been created outside the script, the DROP TABLE statements
will raise error messages, but these can be ignored. It is of course essential, if the tables contain data, to
ensure this has been copied to other tables before such a restructuring exercise is undertaken.

Review Questions

1. Create the following tables, choosing appropriate data types for the attributes of each table. In your
CREATE TABLE statements, create primary keys for both tables, and an appropriate foreign key for the
student table.

• TUTOR (TUTOR_ID, TUTOR_NAME, DEPARTMENT, SALARY, ADVICE_TIME)


• STUDENT(STUDENT_NO, STUDENT_NAME, DATE_JOINED, COURSE, TUTOR_ID)

2. Which of these two relations would you create first (TUTOR or STUDENT) and why?

3. Ensure that the STUDENT_NO field is sufficiently large to accommodate over 10,000 students. If it is not,
change it so that it can deal with this situation.

4. Add an ANNUAL_LEAVE attribute to the tutor table.

5. Remove the ADVICE_TIME attribute from the tutor table.

6. Insert a row in the TUTOR relation, using any data values of the appropriate type.

10
7. Insert a row in STUDENT for each row in TUTOR, using their TUTOR_ID as their STUDENT_NO and leaving
DATE_JOINED, COURSE and TUTOR_ID as unknown/inapplicable for the moment.

8. Use CREATE TABLE with a sub-query to make copies of your TUTOR and STUDENT relations.

9. Change the TUTOR_ID of the tutor named “Doe” to any new value of the correct type.

10. Remove all students who do not have a tutor.

11. Create a view of the STUDENT relation that contain details of all students taking Computing.

12. Create a view containing the names of all tutors and the names of their tutees.

11

You might also like