You are on page 1of 140

Basic Oracle Handout

Version:2

Revised Edition:November 2009

Structure Query Language (SQL) - Introduction to SQL

Page 2 of 140
WK: 1 - Day: 1.1

Introduction to SQL
1. Overview
The computer industry is criss-crossed with languages and standards, most of which are unintelligible to each other.
Here and there, true standards have emerged, and in these cases it is well worth the time of any programmer to learn
them.
Structured Query Language, or SQL as we commonly call it, has, over the last ten years, emerged as the standard
language for programmers to talk with databases through a Database Management System (DBMS). Oracle,
Microsoft SQL Server, Microsoft Access, IBM's DB2, Sybase, and virtually every other DBMS sold in the last five
years use SQL. Knowledge of SQL is becoming necessary for almost every IT professional. And as the development
of basic web sites becomes common among non-programmers, a grasp of SQL will help them to integrate data into
their HTML pages.

2. What is SQL & What Does It Do?


Structured Query Language (abbreviated SQL, pronounced to rhyme with equal) is a computer language for
communication with databases. The communicating parties are typically a "front end" which sends a SQL Statement
across a connection to a "back end" that holds the data.
That statement contains instructions to create, read, change or delete data. The universal rules of the language have
been established by ANSI (American National Standards Institute); a standards committee composed of database
experts from industry, academia and software vendors. Therefore the SQL language is open, meaning it is not owned
or controlled by any single company.

SQL is a non-proprietary (open) language whose rules have been set by a standards committee.

The strength of SQL is its universal acceptance by database vendors. By learning SQL we have a language that can
be used in Visual Basic or C++ to talk to an Oracle database. We can use SQL in an ASP page to talk to Microsoft
SQL Server. We can send a request for data from IBM's DB2 to a Sybase datastore. We can even use SQL within
Access to describe the items we want to include in a form's list box. There has been a lot of talk and marketing about
"write once, run anywhere" languages like Java. For database programmers, understanding SQL is the ticket to
"learn once, profit anywhere. SQL has many capabilities, but the most common needs in business are to:






Read existing data


Create new records holding data
Change existing data
Delete data

SQL contains key words or parts to perform these basic tasks. Learning the basics and embellishments of those
commands will consume most of this book. But before we begin to look at the syntax and lists of common mistakes,
we'll look at some examples of each these operations in the next few paragraphs. Reading data is the most common
task.
An ANSI-SQL statement requesting a list of names of all members of our society that live in New York can be sent
from a Visual Basic application to an Oracle database. If the database is later changed to IBM's DB2, the SQL
statement is still valid. The SQL language offers many permutations of the request, including the ability to return the
names in various orders, only the first or last few names, a list of names without duplicates and various other
requests where people require specific information from their database.
Records can be created in a datastore using SQL. A form page on a web site can gather information from a visitor
and then put that data into a SQL statement. The SQL statement will instruct the datastore to insert a new record into
a Microsoft SQL Server database. Since SQL is universally accepted, the same SQL statement could, for example,
be used for clerks that create new records from, say, a Visual Basic application on their local network.
Data can also be changed using SQL. As in the examples above, a front end user interface such as a web page can
accept changes to data and send them via a SQL statement to the datastore. But there does not have to be direct
user interaction. A DB2 database running on an IBM mainframe could have a procedure to connect to another
corporate mainframe running Sybase.
The IBM can generate and send a SQL statement to modify the data in certain records in the Sybase database.
Although the systems are from different vendors and have different ways of storing and using data, they both
understand the SQL statement. Deleting data can be performed using SQL statements. In fact SQL can
accommodate very complex sets of conditions for which records to delete and which to leave intact. Portions of data
within a record can be deleted.

Structure Query Language (SQL) - Introduction to SQL

Page 3 of 140
WK: 1 - Day: 1.1

3. What Does SQL Not Do?


First, SQL is not a program or a development environment such as Access or VB. SQL is a pure language. There is
no front end built into SQL, that is, the language does not have user forms like an Access application or Visual Basic,
and SQL has no intrinsic way to talk with web pages. SQL statements are mainly generated by a separate front-end
product. Many SQL-enabled DBMS do have a tool that allows us to type a SQL statement and run it against the data.
But these tools are only for design time, not deployment.
Second, SQL does not have a back end. There are no tools intrinsic to the language that can actually store data. SQL
is only a standard means of communicating with software products that can hold data (a DBMS as we will see later).
In other words, the data itself is contained within a DBMS such as Oracle or SQL Server. We will also need a front
end, such as VB or C++. Then we can use SQL as the language for the front end to send instructions to the DBMS.
To take these first two points together, SQL is a language and not a software product. Consider a spoken language;
the language itself does not contain a speaker or a listener. The language only contains the vocabulary, grammatical
rules and idioms to be used by speakers and listeners. The people are not part of, or specified in any way, by the
language. SQL is like a spoken language in another way. The listener and speaker can have any mother tongue, as
long as they can translate that to SQL. So a computer can use any operating system and any database software, as
long as the software can translate from its internal language to SQL.

SQL is a language, not a software product. Front-end software interfaces with the user. Back-end
software holds data. SQL is the standard language for the two pieces of software to communicate with each
other.
Third, SQL is not a procedural programming language. We will discuss the concepts of declarative versus procedural
languages shortly. SQL is a set-based language, which communicates in statements that define an outcome. This is
very different to procedural languages that instruct the computer how to proceed step by step to reach an objective.
Fourth, SQL does not have its own specific development environment. When we work with Access or Power Builder,
for example, we have a highly evolved set of tools for:






laying out our user interface


troubleshooting
rapid entry of code
code reuse

But pure SQL does not include any of those tools (although most vendors include some tools in their products, they
are not part of pure SQL). To go back to our spoken language analogy, SQL is the language. It is not a dictionary,
grammar guide, printing press, loudspeaker, postal service, filing cabinet or any of the other tools we use to work with
human languages. In the sense that "English" does not include these tools, neither does the SQL language.
Last, SQL is not network-aware. In the same sense that written English is not dependent on or aware of being used in
telephones or e-mails, neither is SQL. Whenever a SQL statement is issued there must be a way for it to be
conveyed, or connected, to its destination. Programmers create, maintain and fine- tune those connections with code
in the front and back ends.

4. A Brief History of SQL


In this chapter we want to emphasize that SQL is both deep and wide. Deep in the sense that it is implemented at
many levels of database communication, from a simple Access form list box right up to high-volume communications
between mainframes. SQL is widely implemented in that almost every DBMS supports SQL statements for
communication. The reason for this level of acceptance is partially explained by the amount of effort that went into the
theory and development of the standards.

4.1. Early History


The father of relational databases, and thus SQL, is Dr. E.F. "Ted" Codd who worked for IBM. After Codd described a
relational model for databases in 1970, IBM spent a lot of time and money researching how to implement his ideas.
IBM came to market with a product named System/R in 1978.
But other companies had formed and created relational database products before IBM was ready to release
System/R. The first to market was Relational Software's product named Oracle and the second was Relational
Technology's Ingres. IBM then released improved products in 1982 named SQL/DS and DB2. Oracle (now from
Oracle Inc.) and DB2 are still available today in nth generation forms while the Ingres technology was bought by
Computer Associates.

Structure Query Language (SQL) - Introduction to SQL

Page 4 of 140
WK: 1 - Day: 1.1

4.2. Standards
As we said at the beginning, SQL is a standard, open language without corporate ownership. The commercial
acceptance of SQL was precipitated by the formation of SQL Standards committees by the American National
Standards Institute and the International Standards Organization in 1986 and 1987. Two years later they published a
specification known as SQL-89. An improvement and expansion (to some 600 pages) to the standard gave the world
SQL-92. We now have the third generation standard, SQL 99. The existence of standards is important for the general
portability of SQL statements.
Who is ANSI?
The American National Standards Institute is an administrator and coordinator of voluntary systems of
standardization for the United States private sector. About 80 years ago a group of engineering societies and
government agencies formed the institute to enhance the "quality of life by promoting and facilitating voluntary
consensus standards and conformity." Today the Institute represents the interests of about 1,000 companies,
organizations and government agencies. ANSI does not itself develop standards; rather it facilitates development by
establishing consensus among qualified groups.

4.3. Current State


So the ANSI-SQL group has published three standards over the years:





SQL89 (SQL1)
SQL92 (SQL2)
SQL99 (SQL3)

The vast majority of the language has not changed through these updates. We can all profit from the fact that almost
all of the code we wrote to SQL standards of 1989 is still perfectly usable. Or in other words, as a new student of SQL
there is over ten years of SQL code out there that needs our expertise to maintain and expand.
Most DBMS are designed to meet the SQL92 standard. Virtually all of the material in this book was available in the
earlier standards as well. Since many of the advanced features of SQL92 have yet to be implemented by DBMS
vendors, there has been little pressure for a new version of the standard. Nevertheless a SQL99 standard was
developed to address advanced issues in SQL. All of the core functions of SQL, such as adding, reading and
modifying data, are the same. Therefore, the topics in this book are not affected by the new standard. As of early
2001, no vendor has implemented the SQL99 standard.
There are three areas where there is current development in SQL standards. First entails improving Internet access
to data, particularly to meet the needs of the emerging XML standards. Second is integration with Java, either
through Sun's Java Database Connectivity (JDBC) or through internal implementations. Last, the groups that
establish SQL standards are considering how to integrate object- based programming models.

5. Flavors of SQL
The computer industry (like most industries) both benefits and suffers from standards. We said that SQL is an open
standard, not owned by a company, and the standard comes from ANSI. Therefore the SQL standard from ANSI is
considered the "pure" SQL and called ANSI-SQL.
Two problems emerge to sully this pureness. First is that every DBMS vendor wants to differentiate their DBMS
products. So if we look at the feature set of each DBMS product we see that not only does the product support ANSISQL but it also offers extra features, enhancements or extensions that are available only from individual vendors. For
example, most vendors offer a field type which auto- increments even though this is not described in the SQL
standards. These additions to ANSI-SQL are generally proprietary and will not work if we try to use them on
competitor's SQL products. At the level we discuss in this book there are only very minor differences between the
vendors that we will note throughout the book.
Many of these features are powerful and robust, but since they vary from vendor to vendor, programmers should use
them with caution. It is always safest to stick with pure SQL whenever possible; if we stray it should be with full
knowledge that we are losing the portability of our statements (and perhaps even our data).
Such enhancements are not all bad because these extensions are very useful. For example, ANSI-SQL does not
contain an automatic way to assign a serial number to each new record but most DBMS sold today have added this
feature. Since serial numbering is so common programmers are happy to have the enhancement. However, the
method of implementation is not uniform, so code written to get the serial number from data in one DBMS may not
work when used with another vendor's DBMS.

Structure Query Language (SQL) - Introduction to SQL

Page 5 of 140
WK: 1 - Day: 1.1

How SQL Works


The strengths of SQL provide benefits for all types of users, including application programmers, database
administrators, managers, and end users. Technically speaking, SQL is a data sublanguage. The purpose of SQL is
to provide an interface to a relational database such as Oracle Database, and all SQL statements are instructions to
the database. In this SQL differs from general-purpose programming languages like C and BASIC. Among the
features of SQL are the following:





It processes sets of data as groups rather than as individual units.


It provides automatic navigation to the data.
It uses statements that are complex and powerful individually, and that therefore stand alone. Flow-control
statements were not part of SQL originally, but they are found in the recently accepted optional part of SQL,
ISO/IEC 9075-5: 1996. Flow-control statements are commonly known as "persistent stored modules" (PSM),
and the PL/SQL extension to Oracle SQL is similar to PSM.

SQL lets we work with data at the logical level. We need to be concerned with the implementation details only when
we want to manipulate the data. For example, to retrieve a set of rows from a table, we define a condition used to
filter the rows. All rows satisfying the condition are retrieved in a single step and can be passed as a unit to the user,
to another SQL statement, or to an application. We need not deal with the rows one by one, nor do we have to worry
about how they are physically stored or retrieved. All SQL statements use the optimizer, a part of Oracle Database
that determines the most efficient means of accessing the specified data. Oracle also provides techniques that we
can use to make the optimizer perform its job better.
SQL provides statements for a variety of tasks, including:







Querying data
Inserting, updating, and deleting rows in a table
Creating, replacing, altering, and dropping objects
Controlling access to the database and its objects
Guaranteeing database consistency and integrity

SQL unifies all of the preceding tasks in one consistent language.

Structure Query Language (SQL) - Introduction to DBMS

Page 6 of 140
WK: 1 - Day: 1.1

Database Management System (DBMS)


A database management system (DBMS) is a computer program (or more typically, a suite of them) designed to
manage a database (a large set of structured data), and run operations on the data requested by numerous clients.
Typical examples of DBMS use include accounting, human resources and customer support systems. Originally
found only in large organizations with the computer hardware needed to support large data sets, DBMSs have more
recently emerged as a fairly standard part of any company back office.
DBMS's are found at the heart of most database applications. Sometimes DBMSs are built around a private
multitasking kernel with built-in networking support although nowadays these functions are left to the operating
system.
A database management system (DBMS) is a system, usually automated and computerized, for the management
of any collection of compatible, and ideally normalized, data.
A database application is computer software written to manage the data of a particular application or problem.

1. History
Databases have been in use since the earliest days of electronic computing, but the vast majority of these were
custom programs written to access custom databases. Unlike modern systems which can be applied to widely
different databases and needs, these systems were tightly linked to the database in order to gain speed at the
expense of flexibility.

1.1. Navigational DBMS


As computers grew in capability, this tradeoff became increasingly unnecessary and a number of general-purpose
database systems emerged; by the mid-1960s there were a number of such systems in commercial use. Interest in a
standard began to grow, and Charles Bachman, author of one such product, IDS, founded the Database Task Group
within CODASYL, the group responsible for the creation and standardization of COBOL. In 1971 they delivered their
standard, which generally became known as the Codasyl approach, and soon there were a number of commercial
products based on it available.
The Codasyl approach was based on the "manual" navigation of a linked dataset which was formed into a large
network. When the database was first opened, the program was handed back a link to the first record in the
database, which also contained pointers to other pieces of data. To find any particular record the programmer had to
step through these pointers one at a time until the required record was returned. Simple queries like "find all the
people in Sweden" required the program to walk the entire data set and collect the matching results. There was,
essentially, no concept of "find" or "search". This might sound like a serious limitation today, but in an era when the
data was most often stored on magnetic tape such operations were too expensive to contemplate anyway.
IBM also had their own DBMS system in 1968, known as IMS. IMS was a development of software written for the
Apollo program on the System/360. IMS was generally similar in concept to Codasyl, but used a strict hierarchy for its
model of data navigation instead of Codasyl's network model.
Both concepts later became known as navigational databases due to the way data was accessed, and Bachman's
1973 Turing Award award presentation was The Programmer as Navigator. IMS is classified as a hierarchical
database. IDS and IDMS (both CODASYL databases) as well as CINCOMs TOTAL database are classified as
network databases.

1.2. Relational DBMS


Edgar Codd worked at IBM in San Jose, California, in one of their offshoot offices that was primarily involved in the
development of hard disk systems. He was unhappy with the navigational model of the Codasyl approach, notably
the lack of a "search" facility which was becoming increasingly useful when the database was stored on disk instead
of tape. In 1970 he wrote a number of papers that outlined a new approach to database construction that eventually
culminated in the groundbreaking A Relational Model of Data for Large Shared Data Banks.
In this paper he described a new system for storing and working with large databases. Instead of records being
stored in some sort of linked list of free-form records as in Codasyl, Codd's idea was to use a "table" of fixed-length
records. A linked-list system would be very inefficient when storing "sparse" databases where some of the data for
any one record could be left empty. The relational model solved this by splitting the data into a series of normalized
tables, with optional elements being moved out of the main table to where they would take up room only if needed.

Structure Query Language (SQL) - Introduction to DBMS

Page 7 of 140
WK: 1 - Day: 1.1

For instance, a common use of a database system is to track information about users, their name, login information,
various addresses and phone numbers. In the navigational approach all of these data would be placed in a single
record, and unused items would simply not be placed in the database. In the relational approach, the data would be
normalized into a user table, an address table and a phone number table (for instance). Records would be created in
these optional tables only if the address or phone numbers were actually provided.
Linking the information back together is the key to this system. In the relational model some bit of information was
used as a "key", uniquely defining a particular record. When information was being collected about a user,
information stored in the optional (or related) tables would be found by searching for this key. For instance, if the login
name of a user is unique, addresses and phone numbers for that user would be recorded with the login name as its
key. This "re-linking" of related data back into a single collection is something that traditional computer languages are
not designed for.
Just as the navigational approach would require programs to loop in order to collect records, the relational approach
would require loops to collect information about any one record. Codd's solution to the necessary looping was a setoriented language, a suggestion that would later spawn the ubiquitous SQL. Using a branch of mathematics known
as tuple calculus, he demonstrated that such a system could support all the operations of normal databases
(inserting, updating etc.) as well as providing a simple system for finding and returning sets of data in a single
operation.
Codd's paper was picked up by two people at Berkeley, Eugene Wong and Michael Stonebraker. They started a
project known as INGRES using funding that had already been allocated for a geographical database project, using
student programmers to produce code. Beginning in 1973, INGRES delivered its first test products which were
generally ready for widespread use in 1979. During this time a number of people had moved "through" the group
perhaps as many as 30 people worked on the project, about five at a time. INGRES was similar to System R in a
number of ways, including the use of a "language" for data access, known as QUEL - QUEL was in fact relational,
having been based on Codd's own Alpha language, but has since been corrupted to follow SQL, thus violating much
the same concepts of the relational model as SQL itself.
IBM itself did only one test implementation of the relational model, PRTV, and a production one, Business System 12,
both now discontinued. Honeywell did MRDS for Multics, and now there are two new implementations: Alphora
Dataphor and Rel. All other DBMS implementations usually called relational are actually SQL DBMSs.

2. Description of DBMS
A DBMS can be an extremely complex set of software programs that controls the organization, storage and retrieval
of data (fields, records and files) in a database. The basic functionalities that a DBMS must provide are:
1.

A modeling language to define the schema of each database hosted in the DBMS, according to the
DBMS data model.
a.

The three most common organizations are the hierarchical, network and relational models. A
database management system may provide one, two or all three methods. Inverted lists and
other methods are also used. The most suitable structure depends on the application and on
the transaction rate and the number of inquiries that will be made.
The dominant model in use today is the ad hoc one embedded in SQL, a corruption of the
relational model by violating several of its fundamental principles. Many DBMSs also support
the Open Database Connectivity API that supports a standard way for programmers to access
the DBMS.

2.

Data structures optimized to deal with big amounts of data recorded to a permanent data storage device,
which are very slow compared to the primary storage (volatile main memory).

3.

A database query language and report writer to allow users to interactively interrogate the database,
analyse its data and update it according to the users privileges on data.
a.

It also controls the security of the database.

b.

Data security prevents unauthorised users from viewing or updating the database. Using
passwords, users are allowed access to the entire database or subsets of it called subschemas
(pronounced "sub-skeema"). For example, an employee database can contain all the data
about an individual employee, but one group of users may be authorized to view only payroll
data, while others are allowed access to only work history and medical data.

c.

If the DBMS provides a way to interactively enter and update the database, as well as
interrogate it, this capability allows for managing personal databases. However, it may not
leave an audit trail of actions or provide the kinds of controls necessary in a multi-user

Structure Query Language (SQL) - Introduction to DBMS

Page 8 of 140
WK: 1 - Day: 1.1

organisation. These controls are only available when a set of application programs are
customised for each data entry and updating function.
4.

A transaction mechanism, that ideally would guarantee the ACID properties, in order to ensure data
integrity despite of concurrent user access (concurrency control) and faults (fault tolerance).
a.

It also controls the integrity of the database.

b.

The DBMS can maintain the integrity of the database by not allowing more than one user to
update the same record at the same time. The DBMS can keep duplicate records out of the
database; for example, no two customers with the same customer numbers (key fields) can be
entered into the database. See ACID properties for more information (Redundancy avoidance).

The DBMS accepts requests for data from the application program and instructs the operating system to transfer the
appropriate data.
When a DBMS is used, information systems can be changed much more easily as the organization's information
requirements change. New categories of data can be added to the database without disruption to the existing system.
Organizations may use one kind of DBMS for daily transaction processing and then move the detail onto another
computer that uses another DBMS better suited for random inquiries and analysis. Overall systems design decisions
are performed by data administrators and systems analysts. Detailed database design is performed by database
administrators.
Database servers are specially designed computers that hold the actual databases and run only the DBMS and
related software. Database servers are usually multiprocessor computers, with RAID disk arrays used for stable
storage. Connected to one or more servers via a high-speed channel, hardware database accelerators are also used
in large volume transaction processing environments.

Structure Query Language (SQL)- Codd Rules

Page 9 of 140
WK: 1 - Day: 1.1

Codds 12 Rules
Codd's 12 rules are a set of thirteen rules proposed by Edgar F. "Ted" Codd, a pioneer of the relational model for
databases, designed to define what is required from a database management system in order for it to be considered
relational, i.e., a RDBMS.
Codd produced these rules as part of a personal campaign to prevent his vision of the relational database being
diluted, as database vendors scrambled in the early 1980s to repackage existing products with a relational veneer.
Rule 12 was particularly designed to counter such a positioning. In fact, however, the rules are so strict that even
systems whose only interface is the SQL language fail on some of the criteria.

Rule 0: The system must qualify as relational, as a database, and as a management system.
For a system to qualify as a relational database management system (RDBMS), that system must use its relational
facilities (exclusively) to manage the database.

Rule 1: The information rule:


All information in the database to be represented in one and only one way, namely by values in column positions
within rows of tables.

Rule 2: The guaranteed access rule:


All data must be accessible with no ambiguity. This rule is essentially a restatement of the fundamental requirement
for primary keys. It says that every individual scalar value in the database must be logically addressable by specifying
the name of the containing table, the name of the containing column and the primary key value of the containing row.

Rule 3: Systematic treatment of null values:


The DBMS must allow each field to remain null (or empty). Specifically, it must support a representation of "missing
information and inapplicable information" that is systematic, distinct from all regular values (for example, "distinct from
zero or any other number," in the case of numeric values), and independent of data type. It is also implied that such
representations must be manipulated by the DBMS in a systematic way.

Rule 4: Active online catalog based on the relational model:


The system must support an online, inline, relational catalog that is accessible to authorized users by means of their
regular query language. That is, users must be able to access the database's structure (catalog) using the same
query language that they use to access the database's data.

Rule 5: The comprehensive data sublanguage rule:


The system must support at least one relational language that
5.

Has a linear syntax

6.

Can be used both interactively and within application programs,

7.

Supports data definition operations (including view definitions), data manipulation operations (update as
well as retrieval), security and integrity constraints, and transaction management operations (begin,
commit, and rollback).

Rule 6: The view updating rule:


All views that are theoretically updatable must be updatable by the system.

Rule 7: High-level insert, update, and delete:


The system must support set-at-a-time insert, update, and delete operators. This means that data can be retrieved
from a relational database in sets constructed of data from multiple rows and/or multiple tables. This rule states that
insert, update, and delete operations should be supported for any retrievable set rather than just for a single row in a
single table.

Rule 8: Physical data independence:


Changes to the physical level (how the data is stored, whether in arrays or linked lists etc.) must not require a change
to an application based on the structure.

Structure Query Language (SQL)- Codd Rules

Page 10 of 140
WK: 1 - Day: 1.1

Rule 9: Logical data independence:


Changes to the logical level (tables, columns, rows, and so on) must not require a change to an application based on
the structure. Logical data independence is more difficult to achieve than physical data independence.

Rule 10: Integrity independence:


Integrity constraints must be specified separately from application programs and stored in the catalog. It must be
possible to change such constraints as and when appropriate without unnecessarily affecting existing applications.

Rule 11: Distribution independence:


The distribution of portions of the database to various locations should be invisible to users of the database. Existing
applications should continue to operate successfully :
1.

when a distributed version of the DBMS is first introduced; and

2.

when existing distributed data are redistributed around the system.

Rule 12: The nonsubversion rule:


If the system provides a low-level (record-at-a-time) interface, then that interface cannot be used to subvert the
system, for example, bypassing a relational security or integrity constraint.

Structure Query Language (SQL)- Describe Table

Page 11 of 140
WK: 1 - Day: 1.1

Describe Table
Use "Describe" To Get Table Definition
SQLPlus command DESCRIBE returns definitions of tables and views. For example, information about our tables are
stored in the table TABS.
SQL> DESCRIBE TABS;
Name
Null?
-------------------------- -------TABLE_NAME
NOT NULL
TABLESPACE_NAME
CLUSTER_NAME
IOT_NAME
PCT_FREE
PCT_USED
INI_TRANS
MAX_TRANS
INITIAL_EXTENT
NEXT_EXTENT
MIN_EXTENTS
MAX_EXTENTS
PCT_INCREASE
FREELISTS
FREELIST_GROUPS
LOGGING
BACKED_UP
NUM_ROWS
BLOCKS
EMPTY_BLOCKS
AVG_SPACE
CHAIN_CNT
AVG_ROW_LEN
AVG_SPACE_FREELIST_BLOCKS
NUM_FREELIST_BLOCKS
DEGREE
INSTANCES
CACHE
TABLE_LOCK
SAMPLE_SIZE
LAST_ANALYZED
PARTITIONED
IOT_TYPE
TEMPORARY
NESTED
BUFFER_POOL

Type
---VARCHAR2(30)
VARCHAR2(30)
VARCHAR2(30)
VARCHAR2(30)
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
VARCHAR2(3)
VARCHAR2(1)
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
VARCHAR2(10)
VARCHAR2(10)
VARCHAR2(5)
VARCHAR2(8)
NUMBER
DATE
VARCHAR2(3)
VARCHAR2(12)
VARCHAR2(1)
VARCHAR2(3)
VARCHAR2(7)

The first column is the list of column names. The second column is a list of Not Null indicators. The third column is the
list of data types. This output reveals that the column name "TABLE_NAME" is not allowed to be null. Now to get an
alphabetical list of all the tables in our account, use the command
SQL> SELECT TABLE_NAME FROM TABS ORDER BY TABLE_NAME;
We can use the describe command on the following views to obtain information on our account.

View Name

Description

DICT

table names and table description

DICT_COLUMN

column names of table names and column description

CAT

names of all user's tables, views, synonyms, and sequences

OBJ

information on all objects in our account

Structure Query Language (SQL)- Describe Table

TABS

table information on all user's tables

COLS

column information on all user's columns

USER_VIEWS

view information on all user's views

SYN

synonyms information on all user's synonyms

SEQ

sequence information on all user's sequences

Page 12 of 140
WK: 1 - Day: 1.1

USER_CONSTRAINTS constraint information on user's constraints


USER_CONS_COLUMNS column information on user's constraints
IND

index information on all user's indices

USER_IND_COLUMNS column information on user's indices


Often it is used to describe the structure of a table because we may not be familiar with a particular table.









USER: is the owner of the object.


TABLE: is a table, view, or synonym.
DATABASE_LINK_NAME: is the node name and database where object exists. The syntax depends on the
SQL*Net our computer uses. See LINKS for more information on database links.
COLUMN: is the column in table we wish to describe.
OBJECT: is the function or procedure we wish to describe. If we want to describe a procedure in a package,
object is the name of the package.
SUBOBJECT: is the function or procedure in a package that we wish to describe.
For each column, the description lists:
o The column's name
o Whether null values are allowed (NULL or NOT NULL) for the column
o The column's datatype, for example, NUMBER, CHAR, VARCHAR2 (VARCHAR), LONG,
DATE, MLSLABEL, RAW MLSLABEL, RAW, LONGRAW, ROWID.
o The column's precision (and scale, if any, for a numeric column)
For each function or procedure the description lists:
o The type of PL/SQL object (function or procedure)
o The name of the function or procedure
o The arguments, their type, input/output, and default values

Structure Query Language (SQL)-Login Sql

Page 13 of 140
WK: 1 - Day: 1.1

Storing settings for SQL*PLUS (login.sql and glogin.sql)


1. glogin.sql
Whenever SQL*PLUS starts up, it looks for a file named glogin.sql under the directory
$ORACLE_HOME/sqlplus/admin. If such a file is found, it is read and the containing statements executed. This
allows to store settings (such as linesize) accross SQL*PLUS sessions.
New in Oracle 10g: Oracle also reads glogin.sql and login.sql at a connect in sql*plus.

2. login.sql
Additionally, after reading glogin.sql, sql*plus also looks for a file named login.sql in the directory from where
SQL*PLUS was and in the directory that the environment variable SQLPATH points to and reads it and executes it.
Settings from the login.sql take precedence over settings from glogin.sql

A common login.sql file


A.
B.
C.

SQL> set pagesize 0


SQL> set linesize 190
SQL> define _editor=gvim

Oracle 10g
Since Oracle 10g, the login.sql is executed after a connect
This allows to have a prompt that displays the username. For that, the following line must be in the login.sql:
D.

SQL> set sqlprompt "&_user> "

Structure Query Language (SQL)- SELECT Statements With Operators

Page 14 of 140
WK: 1 - Day: 1.1

SELECT Statements with Operators


1. Overview
To fully use the power of a relational database we need to communicate with it. The ultimate communication would
be to turn to our computer and say, in a clear, distinct voice, "Show me all the left-handed, brown-eyed bean counters
who have worked for this company for at least 10 years." A few of us may already be doing so (talking to our
computer, not listing bean counters). Everyone else needs a more conventional way of retrieving information from the
database. We can make this vital link through SQL's middle name, "Query." The name Query is really a misnomer in
this context. An SQL query is not necessarily a question to the DB. It can be a command to do one of the following:






Build or delete a table


Insert, modify, or delete rows or fields
Search several tables for specific information and return the results in a specific order
Modify security information

A query can also be a simple question to DB. To use this powerful tool, we need to learn how to write an SQL query.

2. General Rules of Syntax


As we will find, syntax in SQL is quite flexible, although there are rules to follow as in any programming language. A
simple query illustrates the basic syntax of an SQL select statement. Pay close attention to the case, spacing, and
logical separation of the components of each query by SQL keywords.
E.
F.
G.

SQL> SELECT ENAME, MGR, HIREDATE


FROM EMP
WHERE ENAME = 'SMITH';

In this example everything is capitalized, but it doesn't have to be. The preceding query would work just as well if it
were written like this:
H.
I.
J.

SQL> SELECT ename, mgr, hiredate


FROM emp
WHERE ename = ' SMITH ';

Note that SIMTH appears in capital letters in both examples. All though actual SQL statements are not case sensitive,
referred to data in DB. For instance, many companies store their data in uppercase. In preceding example, assume
that column ENAME stores its contents in uppercase. Therefore, a query searching for 'Smith' in ENAME column
wouldnt find any data to return. Check our implementation and/or company policies for any case requirements.
Note: Commands in SQL are not case sensitive.
Take another look at the sample query. Is there something magical in the spacing? Again the answer is no. The
following code would work as well:
K.
L.
M.

SQL> SELECT ename, mgr, hiredate


FROM emp
WHERE ename = 'SMITH';

However, some regard for spacing and capitalization makes our statements much easier to read. It also makes our
statements much easier to maintain when they become a part of our project.
Another important feature of (semicolon) semicolon (;) the sample query is the semicolon at the end of the
expression. This punctuation mark tells the command-line SQL program that our query is complete.
If the magic isn't in the capitalization or the format, then just which elements are important? The answer is keywords,
or the words in SQL that are reserved as a part of syntax. (Depending on the SQL statement, a keyword can be
either a mandatory element of the statement or optional.) The keywords in the current example are
N.
O.
P.

SQL> SELECT
FROM
WHERE

Check the table of contents to see some of the SQL keywords we will learn and on what days.

Structure Query Language (SQL)- SELECT Statements With Operators

Page 15 of 140
WK: 1 - Day: 1.1

3. The Building Blocks of Data Retrieval: SELECT and FROM


As our experience with SQL grows, we will notice that we are typing the words SELECT and FROM more than any
other words in the SQL vocabulary. They aren't as glamorous as CREATE or as ruthless as DROP, but they are
indispensable to any conversation we hope to have with the computer concerning data retrieval. And isn't data
retrieval the reason that we entered mountains of information into our very expensive database in the first place?
This discussion starts with SELECT because most of our statements will also start with SELECT:
Syntax:
Q.

SQL> SELECT <COLUMN NAMES>

Basic statements like SELECT couldn't be simpler. However, SELECT does not work alone. If we typed just SELECT
into our system, we might get the following response:
R.
S.
T.
U.
V.

SQL> SELECT;
SELECT
*
ERROR at line 1:
ORA-00936: missing expression

The asterisk under the offending line indicates where Oracle thinks the offense occurred. The error message tells we
that something is missing. That something is the FROM clause:
Syntax:
W.

FROM <TABLE>

Together, the statements SELECT and FROM begin to unlock the power behind our database.
Note: keywords clauses at this point we may be wondering what the difference is between a keyword, a statement,
and a clause. SQL keywords refer to individual SQL elements, such as SELECT and FROM. A clause is a part of an
SQL statement; for example, SELECT column1, column2, ... is a clause. SQL clauses combine to form a complete
SQL statement. For example, we can combine a SELECT clause and a FROM clause to write an SQL statement.
Examples
Before going any further, look at the sample database that is the basis for the following examples. This database
illustrates the basic functions of SELECT and FROM. In the real world we would use the techniques to build this
database, but for the purpose of describing how to use SELECT and FROM, assume database already exists. This
example uses the EMP table to retrieve information about employees that company has.
The EMP table:
X.
Y.
Z.
AA.
BB.
CC.
DD.
EE.
FF.
GG.
HH.
II.
JJ.
KK.
LL.
MM.

EMPNO
----7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934

ENAME
-------SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER

JOB
--------CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK

MGR
---7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782

HIREDATE
--------17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82

SAL
---800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300

COMM DEPTNO
----- -----20
300
30
500
30
20
1400
30
30
10
20
10
0
30
20
30
20
10

MGR

HIREDATE

SAL

COMM

Our First Query


NN.
OO.
PP.

SQL> select * from emp;


EMPNO

ENAME

JOB

DEPTNO

Structure Query Language (SQL)- SELECT Statements With Operators

QQ.
RR.
SS.
TT.
UU.
VV.
WW.
XX.
YY.
ZZ.
AAA.
BBB.
CCC.
DDD.
EEE.

----7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934

-------SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER

--------CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK

---7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782

--------17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82

Page 16 of 140
WK: 1 - Day: 1.1

---800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300

----- -----20
300
30
500
30
20
1400
30
30
10
20
10
0
30
20
30
20
10

Analysis:
This output looks just like the code in the example. Notice that columns 1, 4, 6, 7 and 8 in the output statement are
right-justified and that columns 2, 3 and 5 are left-justified. This format follows the alignment convention in which
numeric data types are right-justified and character data types are left-justified. The asterisk (*) in SELECT * tells the
database to return all the columns associated with the given table described in the FROM clause. The database
determines the order in which to return the columns.

4. Terminating an SQL Statement


In some implementations of SQL, the semicolon at the end of statement tells the interpreter that we are finished
writing the query. For example, Oracle's SQL*PLUS won't execute query until it finds a semicolon (or a slash). On the
other hand, some implementations of SQL dont use the semicolon as a terminator. For example, Microsoft Query
and Borland's ISQL don't require a terminator, because our query is typed in an edit box and executed when we push
a button.

5. Changing the Order of the Columns


The preceding example of an SQL statement used the * to select all columns from a table, order of their appearance
in the output being determined by the database. To specify the order of the columns, we could type something like:
FFF.

SQL> SELECT ename, job, empno, sal FROM emp;

Notice that each column name is listed in the SELECT clause. The order in which the columns are listed is the order
in which they will appear in the output. Notice both the commas that separate the column names and the space
between the final column name and the subsequent clause (in this case FROM). The output would look like this:
GGG.
HHH.
III.
JJJ.
KKK.
LLL.
MMM.
NNN.
OOO.
PPP.
QQQ.
RRR.
SSS.
TTT.
UUU.
VVV.

ENAME
---------SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER

JOB
EMPNO
SAL
--------- ---------- ---------CLERK
7369
800
SALESMAN
7499
1600
SALESMAN
7521
1250
MANAGER
7566
2975
SALESMAN
7654
1250
MANAGER
7698
2850
MANAGER
7782
2450
ANALYST
7788
3000
PRESIDENT
7839
5000
SALESMAN
7844
1500
CLERK
7876
1100
CLERK
7900
950
ANALYST
7902
3000
CLERK
7934
1300

Another way to write the same statement follows.


WWW. SQL> SELECT ename, job, empno, sal

Structure Query Language (SQL)- SELECT Statements With Operators

XXX.

Page 17 of 140
WK: 1 - Day: 1.1

FROM emp;

Notice that the FROM clause has been carried over to the second line. This convention is a matter of personal taste
when writing SQL code. The output would look like this:
YYY.
ZZZ.
AAAA.
BBBB.
CCCC.
DDDD.
EEEE.
FFFF.
GGGG.
HHHH.
IIII.
JJJJ.
KKKK.
LLLL.
MMMM.
NNNN.
OOOO.
PPPP.

ENAME
---------SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER

JOB
EMPNO
SAL
--------- ---------- ---------CLERK
7369
800
SALESMAN
7499
1600
SALESMAN
7521
1250
MANAGER
7566
2975
SALESMAN
7654
1250
MANAGER
7698
2850
MANAGER
7782
2450
ANALYST
7788
3000
PRESIDENT
7839
5000
SALESMAN
7844
1500
CLERK
7876
1100
CLERK
7900
950
ANALYST
7902
3000
CLERK
7934
1300

14 rows selected.

Analysis:
The output is identical because only the format of the statement changed. Now that we have established control over
the order of the columns, we will be able to specify which columns we want to see.

6. Selecting Individual Columns


Suppose we do not want to see every column in the database. We used SELECT * to find out what information was
available, and now we want to concentrate on the employee number and the salary. We type
QQQQ. SQL> SELECT empno, sal
RRRR.
FORM emp;
SSSS.
TTTT.
EMPNO
SAL
UUUU. ---------- ---------VVVV.
7369
800
WWWW.
7499
1600
XXXX.
7521
1250
YYYY.
7566
2975
ZZZZ.
7654
1250
AAAAA.
7698
2850
BBBBB.
7782
2450
CCCCC.
7788
3000
DDDDD.
7839
5000
EEEEE.
7844
1500
FFFFF.
7876
1100
GGGGG.
7900
950
HHHHH.
7902
3000
IIIII.
7934
1300
JJJJJ.
KKKKK. 14 rows selected.

Analysis:
Now we have columns we want to see. Notice use of upper- and lowercase in the query. It did not affect the result.

7. Selecting Different Tables

Structure Query Language (SQL)- SELECT Statements With Operators

Page 18 of 140
WK: 1 - Day: 1.1

Suppose we had a table called DEPT with this structure:


LLLLL.
MMMMM.
NNNNN.
OOOOO.
PPPPP.
QQQQQ.

DEPTNO DNAME
LOC
---------- -------------- --------10 ACCOUNTING
NEW YORK
20 RESEARCH
DALLAS
30 SALES
CHICAGO
40 OPERATIONS
BOSTON

We would simply change the FROM clause to the desired table and type the following statement:
RRRRR. SQL> SELECT * FROM dept;
SSSSS.
TTTTT.
DEPTNO DNAME
LOC
UUUUU. ---------- -------------- --------VVVVV.
10 ACCOUNTING
NEW YORK
WWWWW.
20 RESEARCH
DALLAS
XXXXX.
30 SALES
CHICAGO
YYYYY.
40 OPERATIONS
BOSTON

Analysis:
With a single change we have a new data source.

8. Queries with Distinction


If we look at the original table, EMP, we see that some of the data repeats. For example, if we looked at the MGR
column using
ZZZZZ. SQL> SELECT mgr
AAAAAA.
FROM emp;
BBBBBB.
CCCCCC.
MGR
DDDDDD.
---------EEEEEE.
7902
FFFFFF.
7698
GGGGGG.
7698
HHHHHH.
7839
IIIIII.
7698
JJJJJJ.
7839
KKKKKK.
7839
LLLLLL.
7566
MMMMMM.
NNNNNN.
7698
OOOOOO.
7788
PPPPPP.
7698
QQQQQQ.
7566
RRRRRR.
7782
SSSSSS.
TTTTTT. 14 rows selected.
Notice that the MGR 7698, 7839 and 7566 are repeated. What if we wanted to see how many different MGR are in
this column? Try this:
UUUUUU.
VVVVVV.
WWWWWW.
XXXXXX.
YYYYYY.
ZZZZZZ.
AAAAAAA.
BBBBBBB.
CCCCCCC.

SQL> SELECT DISTINCT mgr


FROM emp;
MGR
---------7566
7698
7782
7788

Structure Query Language (SQL)- SELECT Statements With Operators

DDDDDDD.
EEEEEEE.
FFFFFFF.
GGGGGGG.

Page 19 of 140
WK: 1 - Day: 1.1

7839
7902
7 rows selected.

Analysis:
Notice that only 7 rows are selected. Because we specified DISTINCT, only one instance of the duplicated data is
shown, which means that 7 less row is returned. ALL is a keyword that is implied in the basic SELECT statement. We
almost never see ALL because SELECT <Table> and SELECT ALL <Table> have the same result.
Try this example--for the first (and only!) time in our SQL career:
HHHHHHH.
SQL> SELECT ALL MGR
IIIIIII.
FROM EMP;
JJJJJJJ.
KKKKKKK.
MGR
LLLLLLL.
---------MMMMMMM.
7902
NNNNNNN.
7698
OOOOOOO.
7698
PPPPPPP.
7839
QQQQQQQ.
7698
RRRRRRR.
7839
SSSSSSS.
7839
TTTTTTT.
7566
UUUUUUU.
VVVVVVV.
7698
WWWWWWW.
7788
XXXXXXX.
7698
YYYYYYY.
7566
ZZZZZZZ.
7782
AAAAAAAA.
BBBBBBBB.
14 rows selected.
It is the same as a SELECT <Column>. Who needs the extra keystrokes?

9. Expressions
The definition of an expression is simple: An expression returns a value. Expression types are very broad, covering
different data types such as String, Numeric, and Boolean. In fact, pretty much anything following a clause (SELECT
or FROM, for example) is an expression. In the following example EMPNO is an expression that returns the value
contained in the EMPNO column.
CCCCCCCC.
DDDDDDDD.

SQL> SELECT empno


FROM emp;

In the following statement ENAME, HIREDATE and SAL is expressions:


EEEEEEEE.
FFFFFFFF.

SQL> SELECT ENAME, HIREDATE, SAL


FROM EMP;

Now, examine the following expression:


GGGGGGGG.

WHERE ENAME = 'SMITH'

It contains a condition, NAME = 'SMITH', which is an example of a Boolean expression. NAME = 'SMITH' will be
either TRUE or FALSE, depending on the condition =.

9.1. Conditions
If we ever want to find a particular item or group of items in our database, we need one or more conditions.
Conditions are contained in the WHERE clause. In the preceding example, the condition is

Structure Query Language (SQL)- SELECT Statements With Operators

HHHHHHHH.

Page 20 of 140
WK: 1 - Day: 1.1

ENAME = 'SMITH'

For Ex: to find everyone in our organization that worked more than 100 hours last month, our condition would be
IIIIIIII.

NUMBEROFHOURS > 100

Conditions enable us to make selective queries. In their most common form, conditions comprise a variable, a
constant, and a comparison operator. In the first example the variable is ENAME, the constant is 'SMITH', and the
comparison operator is =. In the second example the variable is NUMBEROFHOURS, the constant is 100, and the
comparison operator is >. We need to know about two more elements before we can write conditional queries: the
WHERE clause and operators.

10. The WHERE Clause


The syntax of the WHERE clause is
Syntax:
JJJJJJJJ.

WHERE <SEARCH CONDITION>

SELECT, FROM, and WHERE are the three most frequently used clauses in SQL. WHERE simply causes our queries to
be more selective. Without the WHERE clause, the most useful thing we could do with a query is display all records in
the selected table(s). For example:
If we wanted a particular employee, we could type
KKKKKKKK.
LLLLLLLL.
MMMMMMMM.
NNNNNNNN.
OOOOOOOO.
PPPPPPPP.
QQQQQQQQ.

SQL> SELECT *
FROM EMP
WHERE ENAME = 'SMITH';
EMPNO
----7369

ENAME
JOB
-------- --------SMITH
CLERK

MGR
---7902

HIREDATE
--------17-DEC-80

SAL
---800

COMM DEPTNO
----- -----20

Analysis:
This simple example shows how we can place a condition on the data that we want to retrieve.

11. Operators
Operators are the elements we use inside an expression to articulate how we want specified conditions to retrieve
data. Operators fall into six groups:








Arithmetic
Comparison
Character
Logical
Set
Miscellaneous

11.1. Arithmetic Operators


The arithmetic operators are plus (+), minus (-), divide (/), multiply (*), and modulo (%). The first four are selfexplanatory. Modulo returns the integer remainder of a division. Here are two examples:
RRRRRRRR.
SSSSSSSS.

5 % 2 = 1
6 % 2 = 0

Modulo operator does not work with data types that have decimals, such as Real or Number.
If we place several of these arithmetic operators in an expression without any parentheses, the operators are
resolved in this order: multiplication, division, modulo, addition, and subtraction. For example, the expression
TTTTTTTT.
Equals

2*6+9/3

Structure Query Language (SQL)- SELECT Statements With Operators

UUUUUUUU.

Page 21 of 140
WK: 1 - Day: 1.1

12 + 3 = 15

However, the expression


VVVVVVVV.

2 * (6 + 9) / 3

Equals
WWWWWWWW. 2 * 15 / 3 = 10
Watch where we put those parentheses! Sometimes the expression does exactly what we tell it to do, rather than
what we want it to do.
The following sections examine the arithmetic operators in some detail and give us a chance to write some queries.

11.1.1. Plus (+)


We can use the plus sign in several ways. Type the following statement to display the PRICE table:
XXXXXXXX.
YYYYYYYY.

SQL> SELECT ENAME, SAL, SAL + 1000


FROM EMP;

Here the + adds 15 cents to each salary to produce the following:


ZZZZZZZZ.
ENAME
SAL
SAL+1000
AAAAAAAAA.
---------- ---------- ---------BBBBBBBBB.
SMITH
800
1800
CCCCCCCCC. ALLEN
1600
2600
DDDDDDDDD. WARD
1250
2250
EEEEEEEEE.
JONES
2975
3975
FFFFFFFFF.
MARTIN
1250
2250
GGGGGGGGG. BLAKE
2850
3850
HHHHHHHHH. CLARK
2450
3450
IIIIIIIII. SCOTT
3000
4000
JJJJJJJJJ.
KING
5000
6000
KKKKKKKKK.
TURNER
1500
2500
LLLLLLLLL.
ADAMS
1100
2100
MMMMMMMMM. JAMES
950
1950
NNNNNNNNN. FORD
3000
4000
OOOOOOOOO. MILLER
1300
2300
PPPPPPPPP.
QQQQQQQQQ. 14 rows selected.

Analysis:
What is this last column with the unattractive column heading SAL+1000? It's not in the original table. (Remember,
we used * in the SELECT clause, which causes all the columns to be shown.) SQL allows us to create a virtual or
derived column by combining or modifying existing columns.

Analysis:
The output confirms that the original data has not been changed and that the column heading SAL+1000 is not a
permanent part of it. In fact, the column heading is so unattractive that we should do something about it.
Type the following:
RRRRRRRRR. SQL> SELECT ENAME, SAL, (SAL + 1000) INCREMENT_SALARY
SSSSSSSSS.
FROM EMP;
TTTTTTTTT.
UUUUUUUUU. ENAME
SAL INCREMENTED_SALARY
VVVVVVVVV.
---------- ---------- -----------------WWWWWWWWW.
SMITH
800
1800
XXXXXXXXX.
ALLEN
1600
2600
YYYYYYYYY.
WARD
1250
2250
ZZZZZZZZZ.
JONES
2975
3975
AAAAAAAAAA. MARTIN
1250
2250

Structure Query Language (SQL)- SELECT Statements With Operators

BBBBBBBBBB. BLAKE
2850
CCCCCCCCCC. CLARK
2450
DDDDDDDDDD. SCOTT
3000
EEEEEEEEEE. KING
5000
FFFFFFFFFF.
TURNER
1500
GGGGGGGGGG.
ADAMS
HHHHHHHHHH. JAMES
950
IIIIIIIIII. FORD
3000
JJJJJJJJJJ.
MILLER
1300
KKKKKKKKKK.
LLLLLLLLLL.
14 rows selected.

Page 22 of 140
WK: 1 - Day: 1.1

3850
3450
4000
6000
2500
1100

2100
1950
4000
2300

Analysis:
This is wonderful! Not only can we create new columns, but we can also rename them on the fly. We can rename any
of the columns using the syntax column_name alias (note the space between column_name and alias).
For example, the query
MMMMMMMMMM.
SQL> SELECT ENAME EMPLOYEE_NAME, SAL, SAL + 1000
INCREMENT_SALARY
NNNNNNNNNN.
FROM EMP;
OOOOOOOOOO.
PPPPPPPPPP. EMPLOYEE_ENAME
SAL INCREMENTED_SALARY
QQQQQQQQQQ.
--------------- ---------- -----------------RRRRRRRRRR. SMITH
800
1800
SSSSSSSSSS. ALLEN
1600
2600
TTTTTTTTTT.
WARD
1250
2250
UUUUUUUUUU. JONES
2975
3975
VVVVVVVVVV. MARTIN
1250
2250
WWWWWWWWWW.
BLAKE
2850
3850
XXXXXXXXXX. CLARK
2450
3450
YYYYYYYYYY. SCOTT
3000
4000
ZZZZZZZZZZ.
KING
5000
6000
AAAAAAAAAAA. TURNER
1500
2500
BBBBBBBBBBB. ADAMS
1100
2100
CCCCCCCCCCC.
JAMES
950
1950
DDDDDDDDDDD.
FORD
3000
4000
EEEEEEEEEEE. MILLER
1300
2300
FFFFFFFFFFF.
GGGGGGGGGGG.
14 rows selected.

11.1.2. Minus (-)


Minus also has 2 uses. First, it can change sign of a number. We can use table HILOW to demonstrate this function.
HHHHHHHHHHH.
SQL> SELECT * FROM HILOW;
IIIIIIIIIII.
JJJJJJJJJJJ.
STATE
HIGHTEMP
LOWTEMP NUMERATOR
N3
N4
KKKKKKKKKKK. ---------- -------- --------- --------- ---LLLLLLLLLLL.
CA
-50
120
10
3
4
MMMMMMMMMMM.
FL
20
110
24
35
46
NNNNNNNNNNN.
LA
15
99
3
23
5
OOOOOOOOOOO.
ND
-70
101
2
45
3
PPPPPPPPPPP. NE
-60
100
1024
1
4

DENOMINATOR

N1

N2

----------- ---- ---- --5

13

23

40

17

63

16

Structure Query Language (SQL)- SELECT Statements With Operators

Page 23 of 140
WK: 1 - Day: 1.1

For example, here's a way to manipulate the data:


QQQQQQQQQQQ.
SQL> SELECT STATE, -HIGHTEMP LOWS, -LOWTEMP HIGHS
RRRRRRRRRRR.
FROM HILOW;
SSSSSSSSSSS.
TTTTTTTTTTT. STATE
LOWS
HIGHS
UUUUUUUUUUU.
---------- -------- --------VVVVVVVVVVV. CA
50
-120
WWWWWWWWWWW. FL
-20
-110
XXXXXXXXXXX. LA
-15
-99
YYYYYYYYYYY. ND
70
-101
ZZZZZZZZZZZ. NE
60
-100
The second (and obvious) use of the minus sign is to subtract one column from another. For example:
AAAAAAAAAAAA.
SQL> SELECT STATE,HIGHTEMP LOWS, LOWTEMP HIGHS, (LOWTEMP HIGHTEMP) DIFFERENCE
BBBBBBBBBBBB.
FROM HILOW;
CCCCCCCCCCCC.
DDDDDDDDDDDD.
STATE
LOWS
HIGHS DIFFERENCE
EEEEEEEEEEEE.
---------- -------- -------- ---------FFFFFFFFFFFF. CA
-50
120
170
GGGGGGGGGGGG.
FL
20
110
90
HHHHHHHHHHHH.
LA
15
99
84
IIIIIIIIIIII. ND
-70
101
171
JJJJJJJJJJJJ.
NE
-60
100
160
Notice the use of aliases to fix the data that was entered incorrectly. This remedy is merely a temporary patch,
though, and not a permanent fix. We should see to it that the data is corrected and entered correctly in the future.
This query not only fixed (at least visually) the incorrect data but also created a new column containing the difference
between the highs and lows of each state. If we accidentally use the minus sign on a character field, we get
something like this:
KKKKKKKKKKKK.
LLLLLLLLLLLL.
MMMMMMMMMMMM.
NNNNNNNNNNNN.
OOOOOOOOOOOO.

SQL> SELECT -STATE FROM HILOW;


ERROR:
ORA-01722: invalid number
no rows selected

The exact error message varies with implementation, but the result is the same.

11.1.3. Divide (/)


The division operator has only the one obvious meaning. Using the table EMP, type the following:
We can show the effects of a two-for-one sale by typing the next statement:
PPPPPPPPPPPP.
SQL> SELECT EMPNO, SAL, (SAL/2) SALARY/2
QQQQQQQQQQQQ.
FROM EMP;
RRRRRRRRRRRR.
SSSSSSSSSSSS.
EMPNO
SAL SALARY/2
TTTTTTTTTTTT. ---------- ---------- -------UUUUUUUUUUUU.
7369
800
400
VVVVVVVVVVVV.
7499
1600
800
WWWWWWWWWWWW.
7521
1250
625
XXXXXXXXXXXX.
7566
2975
1487.5
YYYYYYYYYYYY.
7654
1250
625
ZZZZZZZZZZZZ.
7698
2850
1425
AAAAAAAAAAAAA.
7782
2450
1225
BBBBBBBBBBBBB.
7788
3000
1500
CCCCCCCCCCCCC.
7839
5000
2500
DDDDDDDDDDDDD.
7844
1500
750
EEEEEEEEEEEEE.
7876
1100
550
FFFFFFFFFFFFF.
7900
950
475

Structure Query Language (SQL)- SELECT Statements With Operators

GGGGGGGGGGGGG.
7902
HHHHHHHHHHHHH.
7934
IIIIIIIIIIIII.
JJJJJJJJJJJJJ. 14 rows selected.

3000
1300

Page 24 of 140
WK: 1 - Day: 1.1

1500
650

The use of division in the preceding SELECT statement is straightforward (except that coming up with half salary can
be tough).

11.1.4. Multiply (*)


The multiplication operator is also straight forward. Again, using the EMP table, type the following:
This query changes the table to reflect an across-the-board salary multiply with10:
KKKKKKKKKKKKK.
SQL> SELECT EMPNO, ENAME, SAL, SAL*10 NEWSALARY
LLLLLLLLLLLLL.
FROM EMP;
MMMMMMMMMMMMM.
NNNNNNNNNNNNN.
EMPNO ENAME
SAL NEWSALARY
OOOOOOOOOOOOO.
---------- ---------- ---------- --------PPPPPPPPPPPPP.
7369 SMITH
800
8000
QQQQQQQQQQQQQ.
7499 ALLEN
1600
16000
RRRRRRRRRRRRR.
7521 WARD
1250
12500
SSSSSSSSSSSSS.
7566 JONES
2975
29750
TTTTTTTTTTTTT.
7654 MARTIN
1250
12500
UUUUUUUUUUUUU.
7698 BLAKE
2850
28500
VVVVVVVVVVVVV.
7782 CLARK
2450
24500
WWWWWWWWWWWWW.
7788 SCOTT
3000
30000
XXXXXXXXXXXXX.
7839 KING
5000
50000
YYYYYYYYYYYYY.
7844 TURNER
1500
15000
ZZZZZZZZZZZZZ.
7876 ADAMS
1100
11000
AAAAAAAAAAAAAA.
7900 JAMES
950
9500
BBBBBBBBBBBBBB.
7902 FORD
3000
30000
CCCCCCCCCCCCCC.
7934 MILLER
1300
13000
DDDDDDDDDDDDDD.
EEEEEEEEEEEEEE.
14 rows selected.
These operators enable us to perform powerful calculations in a SELECT statement.

11.1.5. Modulo (%)


Modulo operator returns the integer remainder of the division operation. Using the table HILOW, type the following:
We can also create a new column, REMAINDER, to hold the values of NUMERATOR % DENOMINATOR:
FFFFFFFFFFFFFF.
SQL> SELECT NUMERATOR, DENOMINATOR, NUMERATOR%DENOMINATOR
REMAINDER
GGGGGGGGGGGGGG.
FROM HILOW;
HHHHHHHHHHHHHH.
IIIIIIIIIIIIII.
NUMERATOR DENOMINATOR REMAINDER
JJJJJJJJJJJJJJ. --------- ----------- --------KKKKKKKKKKKKKK.
10
5
0
LLLLLLLLLLLLLL.
8
3
2
MMMMMMMMMMMMMM.
23
9
5
NNNNNNNNNNNNNN.
40
17
6
OOOOOOOOOOOOOO.
1024
16
0
PPPPPPPPPPPPPP.
5 rows selected.
Some implementations of SQL implement modulo as a function called MOD. The following statement produces
results that are identical to the results in the preceding statement:
QQQQQQQQQQQQQQ. SQL> SELECT NUMERATOR, DENOMINATOR,
MOD(NUMERATOR,DENOMINATOR) REMAINDER
RRRRRRRRRRRRRR.
FROM HILOW;

Structure Query Language (SQL)- SELECT Statements With Operators

Page 25 of 140
WK: 1 - Day: 1.1

11.1.6. Precedence
This section examines use of precedence in a SELECT statement. Using the DB HILOW, type the following:
Use the following code segment to test precedence:
SSSSSSSSSSSSSS.
SQL> SELECT N1+N2*N3/N4, (N1+N2)*N3/N4, N1+(N2*N3)/N4
TTTTTTTTTTTTTT.
FROM HILOW;
UUUUUUUUUUUUUU.
VVVVVVVVVVVVVV.
N1+N2*N3/N4 (N1+N2)*N3/N4 N1+(N2*N3)/N4
WWWWWWWWWWWWWW.
----------- ------------- ------------XXXXXXXXXXXXXX.
2.5
2.25
2.5
YYYYYYYYYYYYYY.
31.26087
28.152174
31.26087
ZZZZZZZZZZZZZZ.
22.8
55.2
22.8
AAAAAAAAAAAAAAA.
93
975
93
BBBBBBBBBBBBBBB.
7.5
2.25
7.5
Notice that the first and last columns are identical. If we added a fourth column N1+N2* (N3/N4), its values would
also be identical to those of the current first and last columns.

11.2. Comparison Operators


True to their name, comparison operators compare expressions and return one of three values: TRUE, FALSE, or
Unknown. Wait a minute! Unknown? TRUE and FALSE are self-explanatory, but what is Unknown?
To understand how we could get an Unknown, we need to know a little about the concept of NULL. In DB terms NULL
is the absence of data in a field. It does not mean a column has a zero or a blank in it. A zero or a blank is a value.
NULL means nothing is in that field. If we make a comparison like Field = 9 and the only value for Field is NULL,
the comparison will come back Unknown. Because Unknown is an uncomfortable condition, most flavors of SQL
change Unknown to FALSE and provide a special operator, IS NULL, to test for a NULL condition. Here's an example
of NULL: Suppose an entry in EMP table does not contain a value for COMM. The results of a query might look like this:
CCCCCCCCCCCCCCC. SQL> SELECT * FROM EMP;
DDDDDDDDDDDDDDD.
EEEEEEEEEEEEEEE.
EMPNO ENAME
JOB
MGR
HIREDATE
SAL
DEPTNO
FFFFFFFFFFFFFFF.
----- -------- --------- ---- --------------GGGGGGGGGGGGGGG. 7369 SMITH
CLERK
7902 17-DEC-80
800
20
HHHHHHHHHHHHHHH.
7499 ALLEN
SALESMAN
7698 20-FEB-81
1600
30
IIIIIIIIIIIIIII.
7521 WARD
SALESMAN
7698 22-FEB-81
1250
500
JJJJJJJJJJJJJJJ. 7566 JONES
MANAGER
7839 02-APR-81
2975
KKKKKKKKKKKKKKK.
7654 MARTIN
SALESMAN
7698 28-SEP-81
1250
30
LLLLLLLLLLLLLLL.
7698 BLAKE
MANAGER
7839 01-MAY-81
2850
30
MMMMMMMMMMMMMMM.
7782 CLARK
MANAGER
7839 09-JUN-81
10
NNNNNNNNNNNNNNN.
7788 SCOTT
ANALYST
7566 19-APR-87
3000
20
OOOOOOOOOOOOOOO. 7839 KING
PRESIDENT
17-NOV-81
5000
10
PPPPPPPPPPPPPPP.
7844 TURNER
SALESMAN
7698 08-SEP-81
1500
30
QQQQQQQQQQQQQQQ. 7876 ADAMS
CLERK
7788 23-MAY-87
1100
20
RRRRRRRRRRRRRRR.
7900 JAMES
CLERK
7698 03-DEC-81
950
30
SSSSSSSSSSSSSSS.
7902 FORD
ANALYST
7566 03-DEC-81
3000
20

COMM
----- --

300
30
20
1400

2450

Structure Query Language (SQL)- SELECT Statements With Operators

TTTTTTTTTTTTTTT.
10

7934

MILLER

CLERK

Page 26 of 140
WK: 1 - Day: 1.1

7782

23-JAN-82

1300

Notice that nothing is printed out in the COMM field position for 7934. The value for the field COMM for 7934 is NULL.
The NULL is noticeable in this case because it is in a numeric column. However, if the NULL appeared in the EMPNO
column, it would be impossible to tell the difference between NULL and a blank.
Try to find the NULL:
UUUUUUUUUUUUUUU. SQL> SELECT *
VVVVVVVVVVVVVVV.
FROM EMP
WWWWWWWWWWWWWWW.
WHERE COMM IS NULL;
XXXXXXXXXXXXXXX.
YYYYYYYYYYYYYYY.
EMPNO ENAME
JOB
MGR
HIREDATE
SAL
DEPTNO
ZZZZZZZZZZZZZZZ.
----- -------- --------- ---- --------------AAAAAAAAAAAAAAAA.
7369 SMITH
CLERK
7902 17-DEC-80
800
20
BBBBBBBBBBBBBBBB.
7566 JONES
MANAGER
7839 02-APR-81
2975
20
CCCCCCCCCCCCCCCC. 7698 BLAKE
MANAGER
7839 01-MAY-81
2850
30
DDDDDDDDDDDDDDDD. 7782 CLARK
MANAGER
7839 09-JUN-81
2450
10
EEEEEEEEEEEEEEEE.
7788 SCOTT
ANALYST
7566 19-APR-87
3000
20
FFFFFFFFFFFFFFFF.
7839 KING
PRESIDENT
17-NOV-81
5000
10
GGGGGGGGGGGGGGGG.
7876 ADAMS
CLERK
7788 23-MAY-87
20
HHHHHHHHHHHHHHHH. 7900 JAMES
CLERK
7698 03-DEC-81
950
30
IIIIIIIIIIIIIIII.
7902 FORD
ANALYST
7566 03-DEC-81
3000
JJJJJJJJJJJJJJJJ.
7934 MILLER
CLERK
7782 23-JAN-82
1300
10

COMM
----- --

1100

20

Analysis:
As we can see by the output, the above EMPNO whose value for COMM is NULL or does not contain a value. What if we
use the equal sign (=) instead?
KKKKKKKKKKKKKKKK. SQL> SELECT *
LLLLLLLLLLLLLLLL.
FROM EMP
MMMMMMMMMMMMMMMM.
WHERE COMM = NULL;
NNNNNNNNNNNNNNNN.
OOOOOOOOOOOOOOOO.
no rows selected

Analysis:
We didn't find anything because the comparison COMM = NULL returned a FALSE the result is unknown. It would be
more appropriate to use an IS NULL instead of =, changing the WHERE statement to WHERE COMM IS NULL. In this
case we would get all the rows where a NULL existed.
This example also illustrates both the use of the most common comparison operator, the equal sign (=), and the
playground of all comparison operators, the WHERE clause. We already know about the WHERE clause, so here's a
brief look at the equal sign.

11.2.1. Equal (=)


Earlier we saw how some implementations of SQL use the equal sign in the SELECT clause to assign an alias. In the
WHERE clause, the equal sign is the most commonly used comparison operator. Used alone, the equal sign is a very
convenient way of selecting one value out of many. Try this:

Structure Query Language (SQL)- SELECT Statements With Operators

Page 27 of 140
WK: 1 - Day: 1.1

Let's find SMITH row from EMP table. (On a short list this task appears trivial, but we may have more friends than we
do or we may have a list with thousands of records.)
PPPPPPPPPPPPPPPP. SQL> SELECT *
QQQQQQQQQQQQQQQQ.
FROM EMP
RRRRRRRRRRRRRRRR.
WHERE ENAME = 'SMITH';
SSSSSSSSSSSSSSSS.
TTTTTTTTTTTTTTTT.
EMPNO ENAME
JOB
MGR
DEPTNO
UUUUUUUUUUUUUUUU. ----- -------- --------- ------VVVVVVVVVVVVVVVV.
7369 SMITH
CLERK
7902
20

HIREDATE

SAL

COMM

---------

----

----- --

17-DEC-80

800

We got the result that we expected. Try this:


WWWWWWWWWWWWWWWW. SQL> SELECT *
XXXXXXXXXXXXXXXX.
FROM EMP
YYYYYYYYYYYYYYYY.
WHERE JOB = 'ANALYST';
ZZZZZZZZZZZZZZZZ.
AAAAAAAAAAAAAAAAA. EMPNO ENAME
JOB
MGR
DEPTNO
BBBBBBBBBBBBBBBBB. ----- -------- --------- ------CCCCCCCCCCCCCCCCC.
7788 SCOTT
ANALYST
20
DDDDDDDDDDDDDDDDD.
7902 FORD
ANALYST
20

HIREDATE

SAL

COMM

---------

----

----- --

7566

19-APR-87

3000

7566

03-DEC-81

3000

Note: Here we see that = can pull in multiple records.


Here's another very important lesson concerning case sensitivity:
EEEEEEEEEEEEEEEEE. SQL> SELECT * FROM EMP
FFFFFFFFFFFFFFFFF.
WHERE ENAME = 'SMITH';
GGGGGGGGGGGGGGGGG.
HHHHHHHHHHHHHHHHH.
EMPNO ENAME
JOB
MGR
HIREDATE
SAL
COMM DEPTNO
IIIIIIIIIIIIIIIII.
----- -------- --------- ---- ------------ ----- -----JJJJJJJJJJJJJJJJJ.
7369 SMITH
CLERK
7902 17-DEC-80
800
20
KKKKKKKKKKKKKKKKK.
LLLLLLLLLLLLLLLLL.
1 row selected.
Now try this:
MMMMMMMMMMMMMMMMM.
SQL> SELECT * FROM EMP
NNNNNNNNNNNNNNNNN.
WHERE ENAME = 'Smith';
OOOOOOOOOOOOOOOOO.
PPPPPPPPPPPPPPPPP. no rows selected.

Analysis:
Most companies prefer to store data in uppercase to provide data consistency. We should always store data either in
all uppercase or in all lowercase. Mixing case creates difficulties when we try to retrieve accurate data.

11.2.2. Greater Than (>) and Greater Than or Equal To (>=)


The greater than operator (>) works like this:
QQQQQQQQQQQQQQQQQ.
SQL> SELECT *
RRRRRRRRRRRRRRRRR.
FROM EMP
SSSSSSSSSSSSSSSSS.
WHERE SAL > 3000;
TTTTTTTTTTTTTTTTT. EMPNO ENAME
JOB
DEPTNO

MGR

HIREDATE

SAL

COMM

Structure Query Language (SQL)- SELECT Statements With Operators

UUUUUUUUUUUUUUUUU.
------- -----VVVVVVVVVVVVVVVVV. 7839 KING
10

Page 28 of 140
WK: 1 - Day: 1.1

-------- --------PRESIDENT

----

---------

17-NOV-81

----

--

5000

Analysis:
This example found all the salaries greater than (but not including) 3000. To include 3000, type this:
WWWWWWWWWWWWWWWWW.
SQL> SELECT *
XXXXXXXXXXXXXXXXX.
FROM EMP
YYYYYYYYYYYYYYYYY.
WHERE SAL >= 3000;
ZZZZZZZZZZZZZZZZZ.
AAAAAAAAAAAAAAAAAA.
EMPNO ENAME
JOB
COMM DEPTNO
BBBBBBBBBBBBBBBBBB.
----- -------- ----------- -----CCCCCCCCCCCCCCCCCC.
7788 SCOTT
ANALYST
20
DDDDDDDDDDDDDDDDDD.
7839 KING
PRESIDENT
10
EEEEEEEEEEEEEEEEEE.
7902 FORD
ANALYST
20

MGR

HIREDATE

SAL

----

---------

----

7566

19-APR-87

3000

17-NOV-81

5000

03-DEC-81

3000

7566

--

Analysis:
With this change we get salaries starting at 3000 and going up. We could achieve the same results with the
statement SAL > 2999.
Note: Notice that no quotes surround 3000 in this SQL statement. Number defined fields number-defined fields do
not require quotes.

11.2.3. Less Than (<) and Less Than or Equal To (<=)


As we might expect, these comparison operators work the same way as > and >= work, only in reverse:
FFFFFFFFFFFFFFFFFF. SQL> SELECT *
GGGGGGGGGGGGGGGGGG.
FROM EMP
HHHHHHHHHHHHHHHHHH.
WHERE ENAME < 'CLARK;
IIIIIIIIIIIIIIIIII.
JJJJJJJJJJJJJJJJJJ.
EMPNO ENAME
JOB
MGR
HIREDATE
SAL
DEPTNO
KKKKKKKKKKKKKKKKKK.
----- -------- --------- ---- ----------- -----LLLLLLLLLLLLLLLLLL.
7698 BLAKE
MANAGER
7839 01-MAY-81
2850
30
MMMMMMMMMMMMMMMMMM. 7876 ADAMS
CLERK
7788 23-MAY-87
20
NNNNNNNNNNNNNNNNNN.
7499 ALLEN
SALESMAN
7698 20-FEB-81
300
30

COMM
----

--

1100
1600

Analysis:
Did we just use < on a character field? Of course we did. We can use any of these operators on any data type. The
result varies by data type. For example, use lowercase in the following state search:
OOOOOOOOOOOOOOOOOO.
SQL> SELECT *
PPPPPPPPPPPPPPPPPP.
FROM EMP
QQQQQQQQQQQQQQQQQQ.
WHERE ENAME < 'clark';
RRRRRRRRRRRRRRRRRR.
SSSSSSSSSSSSSSSSSS.
EMPNO ENAME
JOB
MGR
HIREDATE
COMM DEPTNO
TTTTTTTTTTTTTTTTTT. ----- -------- --------- ---- ---------------

SAL
----- --

Structure Query Language (SQL)- SELECT Statements With Operators

UUUUUUUUUUUUUUUUUU.
7369
20
VVVVVVVVVVVVVVVVVV.
7566
20
WWWWWWWWWWWWWWWWWW.
2850
30
XXXXXXXXXXXXXXXXXX.
7782
10
YYYYYYYYYYYYYYYYYY.
7788
20
ZZZZZZZZZZZZZZZZZZ. 7839 KING
10
AAAAAAAAAAAAAAAAAAA.
7876
20
BBBBBBBBBBBBBBBBBBB.
7900
30
CCCCCCCCCCCCCCCCCCC.
7902
20
DDDDDDDDDDDDDDDDDDD.
7934
10

Page 29 of 140
WK: 1 - Day: 1.1

SMITH

CLERK

7902

17-DEC-80

800

JONES

MANAGER

7839

02-APR-81

2975

7698

BLAKE

MANAGER

7839

01-MAY-81

CLARK

MANAGER

7839

09-JUN-81

2450

SCOTT

ANALYST

7566

19-APR-87

3000

PRESIDENT

17-NOV-81

5000

ADAMS

CLERK

7788

23-MAY-87

1100

JAMES

CLERK

7698

03-DEC-81

950

FORD

ANALYST

7566

03-DEC-81

3000

MILLER

CLERK

7782

23-JAN-82

1300

Analysis:
Uppercase is usually sorted before lowercase; therefore, the uppercase codes returned are less than 'clark'. Again, to
be safe, check our implementation.
Tip: To be sure of how these operators will behave, check our language tables. Most PC implementations use the
ASCII tables. Some other platforms use EBCDIC.

11.2.4. Inequalities (< > or !=)


When we need to find everything except for certain data, use the inequality symbol, which can be either < > or !=,
depending on our SQL implementation. For example, to find everyone who is not DEPTNO 20, type this:
EEEEEEEEEEEEEEEEEEE.
SQL> SELECT *
FFFFFFFFFFFFFFFFFFF.
FROM EMP
GGGGGGGGGGGGGGGGGGG.
WHERE DEPTNO <> 20;
HHHHHHHHHHHHHHHHHHH.
IIIIIIIIIIIIIIIIIII.
EMPNO ENAME
JOB
MGR
HIREDATE
SAL
COMM DEPTNO
JJJJJJJJJJJJJJJJJJJ.
----- -------- --------- ---- ------------ ----- ----KKKKKKKKKKKKKKKKKKK.
7698 BLAKE
MANAGER
7839 01-MAY-81
2850
30
LLLLLLLLLLLLLLLLLLL.
7782 CLARK
MANAGER
7839 09-JUN-81
2450
10
MMMMMMMMMMMMMMMMMMM.
7839 KING
PRESIDENT
17-NOV-81
5000
10
NNNNNNNNNNNNNNNNNNN.
7900 JAMES
CLERK
7698 03-DEC-81
950
30
OOOOOOOOOOOOOOOOOOO.
7934 MILLER
CLERK
7782 23-JAN-82
1300
10
To find everyone not living in Clerk, type this:
PPPPPPPPPPPPPPPPPPP.
SQL> SELECT *
QQQQQQQQQQQQQQQQQQQ.
FROM EMP
RRRRRRRRRRRRRRRRRRR.
WHERE JOB != 'CLERK';
SSSSSSSSSSSSSSSSSSS.
TTTTTTTTTTTTTTTTTTT. EMPNO ENAME
JOB
MGR
HIREDATE
SAL
DEPTNO
UUUUUUUUUUUUUUUUUUU.
----- -------- --------- ---- ----------- ------

COMM
----

--

Structure Query Language (SQL)- SELECT Statements With Operators

VVVVVVVVVVVVVVVVVVV.
7566
20
WWWWWWWWWWWWWWWWWWW.
2850
30
XXXXXXXXXXXXXXXXXXX.
7782
10
YYYYYYYYYYYYYYYYYYY.
7788
20
ZZZZZZZZZZZZZZZZZZZ. 7839 KING
10
AAAAAAAAAAAAAAAAAAAA.
7902
20

JONES
7698

Page 30 of 140
WK: 1 - Day: 1.1

MANAGER
BLAKE

7839

MANAGER

02-APR-81
7839

2975

01-MAY-81

CLARK

MANAGER

7839

09-JUN-81

2450

SCOTT

ANALYST

7566

19-APR-87

3000

PRESIDENT
FORD

ANALYST

17-NOV-81
7566

5000

03-DEC-81

3000

Note: Notice that both symbols, <> and !=, can express "not equals."

11.3. Character Operators


We can use character operators to manipulate the way character strings are represented, both in the output of data
and in the process of placing conditions on data to be retrieved. This section describes two character operators: the
LIKE operator and the || operator, which conveys the concept of character concatenation.

11.3.1. Like
What if we wanted to select parts of a database that fit a pattern but weren't quite exact matches? We could use the
equal sign and run through all the possible cases, but that process would be boring and time-consuming. Instead, we
could use LIKE. Consider the following:
How can we find all the employees whose name starts have OT in there name? A quick visual inspection of this
simple table shows that it has two parts, but unfortunately the locations have slightly different names. Try this:
BBBBBBBBBBBBBBBBBBBB.
SQL> SELECT *
CCCCCCCCCCCCCCCCCCCC.
FROM EMP
DDDDDDDDDDDDDDDDDDDD.
WHERE ENAME LIKE '%OT%';
EEEEEEEEEEEEEEEEEEEE.
FFFFFFFFFFFFFFFFFFFF.
EMPNO ENAME
JOB
MGR
COMM DEPTNO
GGGGGGGGGGGGGGGGGGGG. ----- -------- --------- ------ -----HHHHHHHHHHHHHHHHHHHH.
7788 SCOTT
ANALYST
7566
20

HIREDATE

SAL

---------

----

19-APR-87

3000

--

Analysis:
We can see the use of the percent sign (%) in the statement after LIKE. When used inside a LIKE expression, % is a
wildcard. What we asked for was any occurrence of OT in the column location. If we queried
IIIIIIIIIIIIIIIIIIII.
SQL> SELECT *
JJJJJJJJJJJJJJJJJJJJ.
FROM EMP
KKKKKKKKKKKKKKKKKKKK.
WHERE ENAME LIKE 'SC%';
we would get any occurrence that started with SC:
LLLLLLLLLLLLLLLLLLLL. EMPNO ENAME
JOB
MGR
HIREDATE
SAL
COMM
DEPTNO
MMMMMMMMMMMMMMMMMMMM.
----- -------- --------- ---- ----------- ----- -----NNNNNNNNNNNNNNNNNNNN.
7788 SCOTT
ANALYST
7566 19-APR-87
3000
20
If we queried
OOOOOOOOOOOOOOOOOOOO. SQL> SELECT *
PPPPPPPPPPPPPPPPPPPP.
FROM EMP
QQQQQQQQQQQQQQQQQQQQ.
WHERE ENAME LIKE 'A%';

Structure Query Language (SQL)- SELECT Statements With Operators

Page 31 of 140
WK: 1 - Day: 1.1

we would get any name that starts with A:


RRRRRRRRRRRRRRRRRRRR.
COMM DEPTNO
SSSSSSSSSSSSSSSSSSSS.
--- -----TTTTTTTTTTTTTTTTTTTT.
300
30
UUUUUUUUUUUUUUUUUUUU.
20

EMPNO

ENAME

-----

JOB

MGR

HIREDATE

SAL

-------- ---------

----

---------

----

7499

ALLEN

SALESMAN

7698

20-FEB-81

1600

7876

ADAMS

CLERK

7788

23-MAY-87

1100

--

Is LIKE case sensitive? Try the next query to find out.


VVVVVVVVVVVVVVVVVVVV.
SQL> SELECT *
WWWWWWWWWWWWWWWWWWWW.
FROM EMP
XXXXXXXXXXXXXXXXXXXX.
WHERE ENAME LIKE 'a%';
YYYYYYYYYYYYYYYYYYYY.
ZZZZZZZZZZZZZZZZZZZZ.
no rows selected

Analysis:
The answer is yes. References to data are always case sensitive. What if we want to find data that matches all but
one character in a certain pattern? In this case we could use a different type of wildcard: the underscore.

11.3.2. Underscore (_)


The underscore is the single-character wildcard. To find all the records where DEPTNO starts with 1, type the
following:
AAAAAAAAAAAAAAAAAAAAA.
SQL> SELECT *
BBBBBBBBBBBBBBBBBBBBB.
FROM EMP
CCCCCCCCCCCCCCCCCCCCC.
WHERE DEPTNO LIKE '1_';
DDDDDDDDDDDDDDDDDDDDD.
EEEEEEEEEEEEEEEEEEEEE.
EMPNO ENAME
JOB
MGR
HIREDATE
SAL
COMM DEPTNO
FFFFFFFFFFFFFFFFFFFFF.
----- -------- --------- ---- ------------ ---- -----GGGGGGGGGGGGGGGGGGGGG.
7782 CLARK
MANAGER
7839 09-JUN-81
2450
10
HHHHHHHHHHHHHHHHHHHHH. 7839 KING
PRESIDENT
17-NOV-81
5000
10
IIIIIIIIIIIIIIIIIIIII.
7934 MILLER
CLERK
7782 23-JAN-82
1300
10
We can use several underscores in a statement:
JJJJJJJJJJJJJJJJJJJJJ. SQL> SELECT *
KKKKKKKKKKKKKKKKKKKKK.
FROM ENAME
LLLLLLLLLLLLLLLLLLLLL.
WHERE ENAME LIKE'SC_T_';
MMMMMMMMMMMMMMMMMMMMM.
NNNNNNNNNNNNNNNNNNNNN. EMPNO ENAME
JOB
MGR
HIREDATE
SAL
COMM DEPTNO
OOOOOOOOOOOOOOOOOOOOO.
----- -------- --------- ---- ----------- ----- -----PPPPPPPPPPPPPPPPPPPPP.
7788 SCOTT
ANALYST
7566 19-APR-87
3000
20
The previous statement could also be written as follows:
QQQQQQQQQQQQQQQQQQQQQ.
SQL> SELECT *
RRRRRRRRRRRRRRRRRRRRR.
FROM EMP
SSSSSSSSSSSSSSSSSSSSS.
WHERE ENAME LIKE 'SCO_%';
TTTTTTTTTTTTTTTTTTTTT.
UUUUUUUUUUUUUUUUUUUUU. EMPNO ENAME
JOB
MGR
COMM DEPTNO

HIREDATE

SAL

Structure Query Language (SQL)- SELECT Statements With Operators

Page 32 of 140
WK: 1 - Day: 1.1

VVVVVVVVVVVVVVVVVVVVV.
----- -------- --------- ---- -------------- -----WWWWWWWWWWWWWWWWWWWWW.
7788 SCOTT
ANALYST
7566 19APR-87
3000
20

--

Notice that the results are identical. These two wildcards can be combined. The next example finds all records with L
as the second character:
XXXXXXXXXXXXXXXXXXXXX.
SQL> SELECT *
YYYYYYYYYYYYYYYYYYYYY.
FROM EMP
ZZZZZZZZZZZZZZZZZZZZZ.
WHERE ENAME LIKE '_L%';
AAAAAAAAAAAAAAAAAAAAAA.
BBBBBBBBBBBBBBBBBBBBBB. EMPNO ENAME
JOB
MGR
HIREDATE
SAL
COMM DEPTNO
CCCCCCCCCCCCCCCCCCCCCC.
----- -------- --------- ---- ----------- ----- -----DDDDDDDDDDDDDDDDDDDDDD.
7499 ALLEN
SALESMAN
7698 20-FEB-81
1600
300
30
EEEEEEEEEEEEEEEEEEEEEE.
7698 BLAKE
MANAGER
7839 01-MAY-81
2850
30
FFFFFFFFFFFFFFFFFFFFFF.
7782 CLARK
MANAGER
7839 09-JUN-81
2450
10

11.3.3. Concatenation (||)


The || (double pipe) symbol concatenates two strings. Try this:
GGGGGGGGGGGGGGGGGGGGGG.
SQL> SELECT DEPTNO || DNAME CODE_NAME
HHHHHHHHHHHHHHHHHHHHHH.
FROM DEPT;
IIIIIIIIIIIIIIIIIIIIII.
JJJJJJJJJJJJJJJJJJJJJJ. CODE_NAME
KKKKKKKKKKKKKKKKKKKKKK. ----------------------------------------------------LLLLLLLLLLLLLLLLLLLLLL.
10 ACCOUNTING
MMMMMMMMMMMMMMMMMMMMMM. 20 RESEARCH
NNNNNNNNNNNNNNNNNNNNNN.
30 SALES
OOOOOOOOOOOOOOOOOOOOOO.
40 OPERATIONS
PPPPPPPPPPPPPPPPPPPPPP.
QQQQQQQQQQQQQQQQQQQQQQ.
4 rows selected.

Analysis:
Notice that || is used instead of +. If we use + to try to concatenate the strings, the SQL interpreter used for this
example returns the following error:
RRRRRRRRRRRRRRRRRRRRRR.
SQL> SELECT DEPTNO + DNAME CODE_NAME
SSSSSSSSSSSSSSSSSSSSSS.
FROM DEPT;
TTTTTTTTTTTTTTTTTTTTTT.
ERROR:
UUUUUUUUUUUUUUUUUUUUUU.
ORA-01722: invalid number
It is looking for two numbers to add and throws the error invalid number when it doesn't find any.
Note: Some implementations of SQL use the plus sign to concatenate strings. Check our implementation. Here's a
more practical example using concatenation:
VVVVVVVVVVVVVVVVVVVVVV. SQL> SELECT DEPTNO || ',' || DNAME CODE_NAME
WWWWWWWWWWWWWWWWWWWWWW.
FROM DEPT;
XXXXXXXXXXXXXXXXXXXXXX.
YYYYYYYYYYYYYYYYYYYYYY. CODE_NAME
ZZZZZZZZZZZZZZZZZZZZZZ.
----------------------------------------------------AAAAAAAAAAAAAAAAAAAAAAA. 10 , ACCOUNTING
BBBBBBBBBBBBBBBBBBBBBBB. 20 , RESEARCH
CCCCCCCCCCCCCCCCCCCCCCC.
30 , SALES

Structure Query Language (SQL)- SELECT Statements With Operators

DDDDDDDDDDDDDDDDDDDDDDD.

Page 33 of 140
WK: 1 - Day: 1.1

40 , OPERATIONS

Analysis:
This statement inserted a comma between the DEPTNO and the DNAME.
Note: The extra spaces between the first name and the last name in these examples. These spaces are actually part
of the data. With certain data types, spaces are right-padded to values less than the total length allocated for a field.

11.4. Logical Operators


Logical operators separate two or more conditions in the WHERE clause of an SQL statement. Vacation time is always
a hot topic around the workplace. Say we designed a table called VACATION for the accounting department:
EEEEEEEEEEEEEEEEEEEEEEE. SQL> SELECT * FROM VACATION;
FFFFFFFFFFFFFFFFFFFFFFF.
GGGGGGGGGGGGGGGGGGGGGGG.
LASTNAME
EMPLOYEENUM
YEARS
LEAVETAKEN
HHHHHHHHHHHHHHHHHHHHHHH.
-------------- ----------- --------- --------IIIIIIIIIIIIIIIIIIIIIII. ABLE
101
2
4
JJJJJJJJJJJJJJJJJJJJJJJ. BAKER
104
5
23
KKKKKKKKKKKKKKKKKKKKKKK. BLEDSOE
107
8
45
LLLLLLLLLLLLLLLLLLLLLLL.
BOLIVAR
233
4
80
MMMMMMMMMMMMMMMMMMMMMMM. BOLD
210
15
100
NNNNNNNNNNNNNNNNNNNNNNN.
COSTALES
211
10
78
OOOOOOOOOOOOOOOOOOOOOOO.
PPPPPPPPPPPPPPPPPPPPPPP. 6 rows selected.
Suppose our company gives each employee 12 days of leave each year. Using what we have learned and a logical
operator, find all the employees whose names start with B and who have more than 50 days of leave coming.
QQQQQQQQQQQQQQQQQQQQQQQ.
SQL> SELECT LASTNAME, YEARS * 12 - LEAVETAKEN
REMAINING
RRRRRRRRRRRRRRRRRRRRRRR.
FROM VACATION
SSSSSSSSSSSSSSSSSSSSSSS.
WHERE LASTNAME LIKE 'B%' AND YEARS * 12 LEAVETAKEN > 50;
TTTTTTTTTTTTTTTTTTTTTTT.
UUUUUUUUUUUUUUUUUUUUUUU.
LASTNAME
REMAINING
VVVVVVVVVVVVVVVVVVVVVVV. -------------- --------WWWWWWWWWWWWWWWWWWWWWWW.
BLEDSOE
51
XXXXXXXXXXXXXXXXXXXXXXX. BOLD
80

Analysis:
This query is the most complicated we have done so far. The SELECT clause (lines 1 and 2) uses arithmetic
operators to determine how many days of leave each employee has remaining. The normal precedence computes
YEARS * 12 - LEAVETAKEN. (A clearer approach would be to write (YEARS * 12) - LEAVETAKEN.)
LIKE is used in line 3 with the wildcard % to find all the B names. Line 3 uses the > to find all occurrences greater
than 50. The new element is on line 3. We used the logical operator AND to ensure that we found records that meet
the criteria in lines 3.

11.4.1. AND
AND means that the expressions on both sides must be true to return TRUE. If either expression is false, AND returns
FALSE. For example, to find out which employees have been with the company for 5 years or less and have taken
more than 20 days leave, try this:
YYYYYYYYYYYYYYYYYYYYYYY. SQL> SELECT LASTNAME
ZZZZZZZZZZZZZZZZZZZZZZZ.
FROM VACATION

Structure Query Language (SQL)- SELECT Statements With Operators

Page 34 of 140
WK: 1 - Day: 1.1

AAAAAAAAAAAAAAAAAAAAAAAA.
WHERE YEARS <= 5 AND LEAVETAKEN > 20;
BBBBBBBBBBBBBBBBBBBBBBBB.
CCCCCCCCCCCCCCCCCCCCCCCC.
LASTNAME
DDDDDDDDDDDDDDDDDDDDDDDD.
-------EEEEEEEEEEEEEEEEEEEEEEEE.
BAKER
FFFFFFFFFFFFFFFFFFFFFFFF. BOLIVAR
If we want to know which employees have been with the company for 5 years or more and have taken less than 50
percent of their leave, we could write:
GGGGGGGGGGGGGGGGGGGGGGGG. SQL> SELECT LASTNAME WORKAHOLICS
HHHHHHHHHHHHHHHHHHHHHHHH.
FROM VACATION
IIIIIIIIIIIIIIIIIIIIIIII.
WHERE YEARS >= 5 AND ((YEARS *12)-LEAVETAKEN)/(YEARS * 12) <
0.50;
JJJJJJJJJJJJJJJJJJJJJJJJ.
KKKKKKKKKKKKKKKKKKKKKKKK.
WORKAHOLICS
LLLLLLLLLLLLLLLLLLLLLLLL.
--------------MMMMMMMMMMMMMMMMMMMMMMMM.
BAKER
NNNNNNNNNNNNNNNNNNNNNNNN.
BLEDSOE
Check these people for burnout. Also check out how we used the AND to combine these two conditions.

11.4.2. OR
We can also use OR to sum up a series of conditions. If any of the comparisons is true, OR returns TRUE. To illustrate
the difference, conditions run the last query with OR instead of with AND:
OOOOOOOOOOOOOOOOOOOOOOOO. SQL> SELECT LASTNAME WORKAHOLICS
PPPPPPPPPPPPPPPPPPPPPPPP.
FROM VACATION
QQQQQQQQQQQQQQQQQQQQQQQQ.
WHERE YEARS >= 5 OR ((YEARS *12)LEAVETAKEN)/(YEARS * 12) >= 0.50;
RRRRRRRRRRRRRRRRRRRRRRRR.
SSSSSSSSSSSSSSSSSSSSSSSS.
WORKAHOLICS
TTTTTTTTTTTTTTTTTTTTTTTT. --------------UUUUUUUUUUUUUUUUUUUUUUUU.
ABLE
VVVVVVVVVVVVVVVVVVVVVVVV.
BAKER
WWWWWWWWWWWWWWWWWWWWWWWW. BLEDSOE
XXXXXXXXXXXXXXXXXXXXXXXX.
BOLD
YYYYYYYYYYYYYYYYYYYYYYYY.
COSTALES

Analysis:
The original names are still in the list, but we have three new entries (who would probably resent being called
workaholics). These three new names made the list because they satisfied one of the conditions. OR requires that
only one of the conditions be true in order for data to be returned.

11.4.3. NOT
NOT means just that. If the condition it applies to evaluates to TRUE, NOT make it FALSE. If the condition after the NOT
is FALSE, it becomes TRUE. For example, the following SELECT returns the only two names not beginning with B in
the table:
ZZZZZZZZZZZZZZZZZZZZZZZZ. SQL> SELECT *
AAAAAAAAAAAAAAAAAAAAAAAAA.
FROM VACATION
BBBBBBBBBBBBBBBBBBBBBBBBB.
WHERE LASTNAME NOT LIKE 'B%';
CCCCCCCCCCCCCCCCCCCCCCCCC.
DDDDDDDDDDDDDDDDDDDDDDDDD.
LASTNAME
EMPLOYEENUM
YEARS LEAVETAKEN
EEEEEEEEEEEEEEEEEEEEEEEEE.
-------------- ----------- -------- ---------FFFFFFFFFFFFFFFFFFFFFFFFF. ABLE
101
2
4
GGGGGGGGGGGGGGGGGGGGGGGGG. COSTALES
211
10
78
NOT can also be used with the operator IS when applied to NULL. Recall the EMP table where we put a NULL value in
the COMM column. To find the non-NULL items, type this:

Structure Query Language (SQL)- SELECT Statements With Operators

Page 35 of 140
WK: 1 - Day: 1.1

HHHHHHHHHHHHHHHHHHHHHHHHH.
SQL> SELECT *
IIIIIIIIIIIIIIIIIIIIIIIII.
FROM EMP
JJJJJJJJJJJJJJJJJJJJJJJJJ.
WHERE COMM IS NOT NULL;
KKKKKKKKKKKKKKKKKKKKKKKKK.
LLLLLLLLLLLLLLLLLLLLLLLLL.
EMPNO ENAME
JOB
MGR
HIREDATE
SAL
COMM DEPTNO
MMMMMMMMMMMMMMMMMMMMMMMMM.
----- -------- --------- ---- ----------- ----- -----NNNNNNNNNNNNNNNNNNNNNNNNN.
7499 ALLEN
SALESMAN
7698 20-FEB-81
1600
300
30
OOOOOOOOOOOOOOOOOOOOOOOOO. 7521 WARD
SALESMAN
7698 22-FEB-81
1250
500
30
PPPPPPPPPPPPPPPPPPPPPPPPP.
7654 MARTIN
SALESMAN
7698 28-SEP-81
1250 1400
30
QQQQQQQQQQQQQQQQQQQQQQQQQ. 7844 TURNER
SALESMAN
7698 08-SEP-81
1500
0
30

11.5. Set Operators


11.5.1. UNION and UNION ALL
UNION returns the results of two queries minus the duplicate rows. The following two tables represent the rosters of
teams:
RRRRRRRRRRRRRRRRRRRRRRRRR.
SQL> SELECT * FROM FOOTBALL;
SSSSSSSSSSSSSSSSSSSSSSSSS.
TTTTTTTTTTTTTTTTTTTTTTTTT. NAME
UUUUUUUUUUUUUUUUUUUUUUUUU.
-------------------VVVVVVVVVVVVVVVVVVVVVVVVV.
ABLE
WWWWWWWWWWWWWWWWWWWWWWWWW. BRAVO
XXXXXXXXXXXXXXXXXXXXXXXXX.
CHARLIE
YYYYYYYYYYYYYYYYYYYYYYYYY.
DECON
ZZZZZZZZZZZZZZZZZZZZZZZZZ. EXITOR
AAAAAAAAAAAAAAAAAAAAAAAAAA.
FUBAR
BBBBBBBBBBBBBBBBBBBBBBBBBB.
GOOBER
CCCCCCCCCCCCCCCCCCCCCCCCCC. 7 rows selected.
DDDDDDDDDDDDDDDDDDDDDDDDDD.
EEEEEEEEEEEEEEEEEEEEEEEEEE.
SQL> SELECT * FROM SOFTBALL;
FFFFFFFFFFFFFFFFFFFFFFFFFF.
GGGGGGGGGGGGGGGGGGGGGGGGGG.
NAME
HHHHHHHHHHHHHHHHHHHHHHHHHH. -------------------IIIIIIIIIIIIIIIIIIIIIIIIII. ABLE
JJJJJJJJJJJJJJJJJJJJJJJJJJ.
BAKER
KKKKKKKKKKKKKKKKKKKKKKKKKK.
CHARLIE
LLLLLLLLLLLLLLLLLLLLLLLLLL. DEAN
MMMMMMMMMMMMMMMMMMMMMMMMMM.
EXITOR
NNNNNNNNNNNNNNNNNNNNNNNNNN. FALCONER
OOOOOOOOOOOOOOOOOOOOOOOOOO.
GOOBER
PPPPPPPPPPPPPPPPPPPPPPPPPP.
7 rows selected.
How many different people play on one team or another?
QQQQQQQQQQQQQQQQQQQQQQQQQQ.
SQL> SELECT NAME FROM FOOTBALL
RRRRRRRRRRRRRRRRRRRRRRRRRR.
UNION
SSSSSSSSSSSSSSSSSSSSSSSSSS.
SELECT NAME FROM SOFTBALL;
TTTTTTTTTTTTTTTTTTTTTTTTTT.
UUUUUUUUUUUUUUUUUUUUUUUUUU. NAME
VVVVVVVVVVVVVVVVVVVVVVVVVV.
-------------------WWWWWWWWWWWWWWWWWWWWWWWWWW.
ABLE
XXXXXXXXXXXXXXXXXXXXXXXXXX.
BAKER
YYYYYYYYYYYYYYYYYYYYYYYYYY.
BRAVO

Structure Query Language (SQL)- SELECT Statements With Operators

Page 36 of 140
WK: 1 - Day: 1.1

ZZZZZZZZZZZZZZZZZZZZZZZZZZ.
CHARLIE
AAAAAAAAAAAAAAAAAAAAAAAAAAA.
DEAN
BBBBBBBBBBBBBBBBBBBBBBBBBBB.
DECON
CCCCCCCCCCCCCCCCCCCCCCCCCCC. EXITOR
DDDDDDDDDDDDDDDDDDDDDDDDDDD. FALCONER
EEEEEEEEEEEEEEEEEEEEEEEEEEE.
FUBAR
FFFFFFFFFFFFFFFFFFFFFFFFFFF.
GOOBER
GGGGGGGGGGGGGGGGGGGGGGGGGGG.
10 rows selected.
UNION returns 10 distinct names from the two lists. How many names are on both lists (including duplicates)?
HHHHHHHHHHHHHHHHHHHHHHHHHHH. SQL> SELECT NAME FROM SOFTBALL
IIIIIIIIIIIIIIIIIIIIIIIIIII.
UNION ALL
JJJJJJJJJJJJJJJJJJJJJJJJJJJ.
SELECT NAME FROM FOOTBALL;
KKKKKKKKKKKKKKKKKKKKKKKKKKK.
LLLLLLLLLLLLLLLLLLLLLLLLLLL. NAME
MMMMMMMMMMMMMMMMMMMMMMMMMMM. -------------------NNNNNNNNNNNNNNNNNNNNNNNNNNN. ABLE
OOOOOOOOOOOOOOOOOOOOOOOOOOO.
BAKER
PPPPPPPPPPPPPPPPPPPPPPPPPPP.
CHARLIE
QQQQQQQQQQQQQQQQQQQQQQQQQQQ.
DEAN
RRRRRRRRRRRRRRRRRRRRRRRRRRR. EXITOR
SSSSSSSSSSSSSSSSSSSSSSSSSSS.
FALCONER
TTTTTTTTTTTTTTTTTTTTTTTTTTT.
GOOBER
UUUUUUUUUUUUUUUUUUUUUUUUUUU. ABLE
VVVVVVVVVVVVVVVVVVVVVVVVVVV.
BRAVO
WWWWWWWWWWWWWWWWWWWWWWWWWWW.
CHARLIE
XXXXXXXXXXXXXXXXXXXXXXXXXXX.
DECON
YYYYYYYYYYYYYYYYYYYYYYYYYYY.
EXITOR
ZZZZZZZZZZZZZZZZZZZZZZZZZZZ.
FUBAR
AAAAAAAAAAAAAAAAAAAAAAAAAAAA. GOOBER
BBBBBBBBBBBBBBBBBBBBBBBBBBBB.
CCCCCCCCCCCCCCCCCCCCCCCCCCCC.
14 rows selected.

Analysis:
The combined list courtesy of the UNION ALL statement has 14 names. UNION ALL works just like UNION except it
does not eliminate duplicates. Now show me a list of players who are on both teams. You can't do that with UNION-you need to learn INTERSECT.

11.5.2. INTERSECT
INTERSECT returns only the rows found by both queries. The next SELECT statement shows the list of players who
play on both teams:
DDDDDDDDDDDDDDDDDDDDDDDDDDDD.
SQL> SELECT * FROM FOOTBALL
EEEEEEEEEEEEEEEEEEEEEEEEEEEE.
INTERSECT
FFFFFFFFFFFFFFFFFFFFFFFFFFFF.
SELECT * FROM SOFTBALL;
GGGGGGGGGGGGGGGGGGGGGGGGGGGG.
NAME
HHHHHHHHHHHHHHHHHHHHHHHHHHHH.
-------------------IIIIIIIIIIIIIIIIIIIIIIIIIIII.
ABLE
JJJJJJJJJJJJJJJJJJJJJJJJJJJJ.
CHARLIE
KKKKKKKKKKKKKKKKKKKKKKKKKKKK. EXITOR
LLLLLLLLLLLLLLLLLLLLLLLLLLLL. GOOBER

Analysis:
In this example INTERSECT finds the short list of players who are on both teams by combining the results of the two
SELECT statements.

Structure Query Language (SQL)- SELECT Statements With Operators

Page 37 of 140
WK: 1 - Day: 1.1

11.5.3. MINUS (Difference)


Minus returns the rows from the first query that were not present in the second. For example:
MMMMMMMMMMMMMMMMMMMMMMMMMMMM.
NNNNNNNNNNNNNNNNNNNNNNNNNNNN.
OOOOOOOOOOOOOOOOOOOOOOOOOOOO.
PPPPPPPPPPPPPPPPPPPPPPPPPPPP.
QQQQQQQQQQQQQQQQQQQQQQQQQQQQ.
RRRRRRRRRRRRRRRRRRRRRRRRRRRR.
SSSSSSSSSSSSSSSSSSSSSSSSSSSS. BRAVO
TTTTTTTTTTTTTTTTTTTTTTTTTTTT.
DECON
UUUUUUUUUUUUUUUUUUUUUUUUUUUU.

SQL> SELECT * FROM FOOTBALL


MINUS
SELECT * FROM SOFTBALL;
NAME
--------------------

FUBAR

Analysis:
The preceding query shows the three football players who are not on the softball team.
VVVVVVVVVVVVVVVVVVVVVVVVVVVV. SQL> SELECT * FROM SOFTBALL
WWWWWWWWWWWWWWWWWWWWWWWWWWWW.
MINUS
XXXXXXXXXXXXXXXXXXXXXXXXXXXX.
SELECT * FROM FOOTBALL;
YYYYYYYYYYYYYYYYYYYYYYYYYYYY.
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.
NAME
AAAAAAAAAAAAAAAAAAAAAAAAAAAAA. -------------------BBBBBBBBBBBBBBBBBBBBBBBBBBBBB. BAKER
CCCCCCCCCCCCCCCCCCCCCCCCCCCCC.
DEAN
DDDDDDDDDDDDDDDDDDDDDDDDDDDDD.
FALCONER

11.6. Miscellaneous Operators: IN and BETWEEN


The two operators IN and BETWEEN provide a shorthand for functions you already know how to do. If you wanted to
find employees in DEPT 10 and 20, you could type the following:
EEEEEEEEEEEEEEEEEEEEEEEEEEEEE. SQL> SELECT *
FFFFFFFFFFFFFFFFFFFFFFFFFFFFF.
FROM EMP
GGGGGGGGGGGGGGGGGGGGGGGGGGGGG.
WHERE DEPTNO = 10 OR DEPTNO = 20;
HHHHHHHHHHHHHHHHHHHHHHHHHHHHH.
IIIIIIIIIIIIIIIIIIIIIIIIIIIII.
EMPNO ENAME
JOB
MGR
HIREDATE
SAL
COMM
DEPTNO
JJJJJJJJJJJJJJJJJJJJJJJJJJJJJ. ----- -------- --------- ---- ------------ ---- -----KKKKKKKKKKKKKKKKKKKKKKKKKKKKK. 7369 SMITH
CLERK
7902 17-DEC-80
800
20
LLLLLLLLLLLLLLLLLLLLLLLLLLLLL.
7566 JONES
MANAGER
7839 02-APR-81
2975
20
MMMMMMMMMMMMMMMMMMMMMMMMMMMMM.
7782 CLARK
MANAGER
7839
09-JUN-81
2450
10
NNNNNNNNNNNNNNNNNNNNNNNNNNNNN.
7788 SCOTT
ANALYST
7566 19APR-87
3000
20
OOOOOOOOOOOOOOOOOOOOOOOOOOOOO.
7839 KING
PRESIDENT
17NOV-81
5000
10
PPPPPPPPPPPPPPPPPPPPPPPPPPPPP. 7876 ADAMS
CLERK
7788 23-MAY-87
1100
20
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQ.
7902 FORD
ANALYST
7566 03DEC-81
3000
20
RRRRRRRRRRRRRRRRRRRRRRRRRRRRR.
7934 MILLER
CLERK
7782 23JAN-82
1300
10
Or you could type this:
SSSSSSSSSSSSSSSSSSSSSSSSSSSSS. SQL> SELECT *
TTTTTTTTTTTTTTTTTTTTTTTTTTTTT.
FROM EMP
UUUUUUUUUUUUUUUUUUUUUUUUUUUUU.
WHERE DEPTNO IN(10,20,30);

Structure Query Language (SQL)- SELECT Statements With Operators

VVVVVVVVVVVVVVVVVVVVVVVVVVVVV.
WWWWWWWWWWWWWWWWWWWWWWWWWWWWW. EMPNO ENAME
JOB
HIREDATE
SAL
COMM DEPTNO
XXXXXXXXXXXXXXXXXXXXXXXXXXXXX. ----- -------- --------- ------ ----- -----YYYYYYYYYYYYYYYYYYYYYYYYYYYYY. 7369 SMITH
CLERK
7902
800
20
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.
7566 JONES
MANAGER
7839
2975
20
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.
7782 CLARK
MANAGER
JUN-81
2450
10
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.
7788 SCOTT
ANALYST
APR-87
3000
20
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.
7839 KING
PRESIDENT
NOV-81
5000
10
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.
7876 ADAMS
CLERK
MAY-87
1100
20
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.
7902 FORD
ANALYST
DEC-81
3000
20
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.
7934 MILLER
CLERK
7782
1300
10

Page 38 of 140
WK: 1 - Day: 1.1

MGR
---------

17-DEC-80
02-APR-81
7839

09-

7566

1917-

7788

23-

7566

03-

23-JAN-82

Analysis:
The second example is shorter and more readable than the first. You never know when you might have to go back
and work on something you wrote months ago. IN also works with characters. Consider the following, where the
column JOB is a number:
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG. SQL> SELECT *
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH.
FROM EMP
IIIIIIIIIIIIIIIIIIIIIIIIIIIIII.
WHERE JOB IN(ANALYST,CLERK);
JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ.
KKKKKKKKKKKKKKKKKKKKKKKKKKKKKK.
EMPNO ENAME
JOB
MGR
HIREDATE
SAL
COMM DEPTNO
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.
----- -------- --------- ---- ----------- ----- -----MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM.
7369 SMITH
CLERK
7902
17-DEC-80
800
20
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNN.
7788 SCOTT
ANALYST
7566 19APR-87
3000
20
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO. 7876 ADAMS
CLERK
7788 23MAY-87
1100
20
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPP.
7900 JAMES
CLERK
7698 03DEC-81
950
30
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ. 7902 FORD
ANALYST
7566 03DEC-81
3000
20
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRR.
7934 MILLER
CLERK
7782 23JAN-82
1300
10
If you needed a range of things from the PRICE table, you could write the following:
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSS.
SQL> SELECT *
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT.
FROM EMP
UUUUUUUUUUUUUUUUUUUUUUUUUUUUUU.
WHERE SAL > 5000 AND
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV.
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW.
EMPNO ENAME
MGR
HIREDATE
SAL
COMM DEPTNO
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.
----- -------- -------------- ----- -----YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY.
7566 JONES
MANAGER
APR-81
2975
20
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.
7698 BLAKE
MANAGER
7839
2850
30

SAL < 2000;


JOB
----

------

7839

02-

01-MAY-81

Structure Query Language (SQL)- SELECT Statements With Operators

A.
B.
C.

7782
7788
7902

CLARK
SCOTT
FORD

MANAGER
ANALYST
ANALYST

7839
7566
7566

09-JUN-81
19-APR-87
03-DEC-81

Page 39 of 140
WK: 1 - Day: 1.1

2450
3000
3000

10
20
20

SAL
---2975
2850
2450
3000
3000

COMM DEPTNO
----- -----20
30
10
20
20

Or using BETWEEN, you would write this:


D.
E.
F.
G.
H.
I.
J.
K.
L.
M.
N.

SQL> SELECT *
FROM EMP
WHERE SAL BETWEEN 2000 AND 5000;
EMPNO
----7566
7698
7782
7788
7902

ENAME
-------JONES
BLAKE
CLARK
SCOTT
FORD

JOB
--------MANAGER
MANAGER
MANAGER
ANALYST
ANALYST

MGR
---7839
7839
7839
7566
7566

HIREDATE
--------02-APR-81
01-MAY-81
09-JUN-81
19-APR-87
03-DEC-81

Again, the second example is a cleaner, more readable solution than the first.
Note: If a SAL value of 2000 existed in the EMP table, that record would have been retrieved also. Parameters used
in the BETWEEN operator are inclusive parameters inclusive.

Structure Query Language (SQL)-Dual Table


140

Page

40

of

WK: 1 - Day: 1.1

Dual Table
The Oracle DUAL table
Dual is a table which is created by oracle along with the data dictionary. It consists of exactly one column whose
name is dummy and one record. The value of that record is X.
O.
P.
Q.
R.
S.
T.
U.
V.
W.
X.

SQL> DESC DUAL


Name
Null?
Type
----------------------- -------- ---------------DUMMY
VARCHAR2(1)
SQL> SELECT * FROM DUAL;
D
X

The owner of dual is SYS but dual can be accessed by every user.
As dual contains exactly one row (unless someone fiddled with it), it is guaranteed to return exactly one row in select
statements if a constant expression is selected against dual, such as in:
Y.

SQL> SELECT SYSDATE FROM DUAL;

Although it is possible to delete the one record, or insert additional records, one really should not do that!.
DUAL is an interesting table - it contains ONE column and ONE record.
Oracle has created this since it makes some calculations more convenient.
For example, we can use it for math:
Z.

SQL> SELECT (319/212)+10 FROM DUAL;

We can use it to increment sequences:


AA.

SQL> SELECT employee_seq.NEXTVAL FROM DUAL;

We can use it to play around or test some SQL:


SQL> SELECT CHR(70) FROM DUAL;

Structure Query Language (SQL)-Functions

Page 41 of 140
WK: 1 - Day: 1.1

Functions
Functions in SQL enable we to perform feats such as determining the sum of a column or converting all the
characters of a string to uppercase. By the end of the day, we will understand and be able to use all the following:








Aggregate functions
Date and time functions
Arithmetic functions
Character functions
Conversion functions
Miscellaneous functions

These functions greatly increase our ability to manipulate the information we retrieved using the basic functions of
SQL. The first five aggregate functions, COUNT, SUM, AVG, MAX, and MIN, are defined in the ANSI standard. Most
implementations of SQL have extensions to these aggregate functions, some of which are covered today. Some
implementations may use different names for these functions.

1. Aggregate Functions
These functions are also referred to as group functions. They return a value based on the values in a column. (After
all, we wouldn't ask for the average of a single field.) The examples in this section use the table TEAMSTATS:
SQL> SELECT * FROM TEAMSTATS;
NAME
POS AB HITS WALKS SINGLES DOUBLES TRIPLES HR SO
--------- --- --- ---- ----- ------- ------- ------- -- -JONES
1B 145
45 34
31
8
1
5 10
DONKNOW
3B 175
65 23
50
10
1
4 15
WORLEY
LF 157
49 15
35
8
3
3 16
DAVID
OF 187
70 24
48
4
0
17 42
HAMHOCKER 3B 50
12 10
10
2
0
0 13
CASEY
DH
1
0 0
0
0
0
0 1
6 rows selected.

1.1. COUNT
The function COUNT returns the number of rows that satisfy the condition in the WHERE clause. Say we wanted to
know how many ball players were hitting under 350. We would type
SQL> SELECT COUNT(*)
FROM TEAMSTATS
WHERE HITS/AB < .35;
COUNT(*)
-------4
To make the code more readable, try an alias:
SQL> SELECT COUNT(*) NUM_BELOW_350
FROM TEAMSTATS
WHERE HITS/AB < .35;
NUM_BELOW_350
------------4
Would it make any difference if we tried a column name instead of the asterisk? (Notice the use of parentheses
around the column names.) Try this:
SQL> SELECT COUNT(NAME) NUM_BELOW_350
FROM TEAMSTATS
WHERE HITS/AB < .35;

Structure Query Language (SQL)-Functions

Page 42 of 140
WK: 1 - Day: 1.1

NUM_BELOW_350
------------4
The answer is no. The NAME column that we selected was not involved in the WHERE statement. If we use COUNT
without a WHERE clause, it returns the number of records in the table.
SQL> SELECT COUNT(*)
FROM TEAMSTATS;
COUNT(*)
--------6

1.2. SUM
SUM does just that. It returns the sum of all values in a column. To find out how many singles have been hit, type
SQL> SELECT SUM(SINGLES) TOTAL_SINGLES
FROM TEAMSTATS;
TOTAL_SINGLES
------------174
To get several sums, use
SQL> SELECT SUM(SINGLES) TOTAL_SINGLES, SUM(DOUBLES) TOTAL_DOUBLES,
SUM(TRIPLES) TOTAL_TRIPLES, SUM(HR) TOTAL_HR
FROM TEAMSTATS;
TOTAL_SINGLES TOTAL_DOUBLES TOTAL_TRIPLES TOTAL_HR
------------- ------------- ------------- -------174
32
5
29
To collect similar information on all 300 or better players, type
SQL> SELECT SUM(SINGLES) TOTAL_SINGLES, SUM(DOUBLES) TOTAL_DOUBLES,
SUM(TRIPLES) TOTAL_TRIPLES, SUM(HR) TOTAL_HR
FROM TEAMSTATS
WHERE HITS/AB >- .300;
TOTAL_SINGLES TOTAL_DOUBLES TOTAL_TRIPLES TOTAL_HR
------------- ------------- ------------- -------164
30
5
29
To compute a team batting average, type
SQL> SELECT SUM(HITS)/SUM(AB) TEAM_AVERAGE
FROM TEAMSTATS;
TEAM_AVERAGE
-----------.33706294
SUM works only with numbers. If we try it on a non-numerical field, we get
SQL> SELECT SUM(NAME)
FROM TEAMSTATS;
***### ERROR:
ORA-01722: invalid number
no rows selected
This error message is logical because we cannot sum a group of names.

1.3. AVG
The AVG function computes the average of a column. To find the average number of strike outs, use this:

Structure Query Language (SQL)-Functions

Page 43 of 140
WK: 1 - Day: 1.1

SQL> SELECT AVG(SO) AVE_STRIKE_OUTS


FROM TEAMSTATS;
AVE_STRIKE_OUTS
--------------16.166667
The following example illustrates the difference between SUM and AVG:
SQL> SELECT AVG(HITS/AB) TEAM_AVERAGE
FROM TEAMSTATS;
TEAM_AVERAGE
-----------.26803448

Analysis:
The team was batting over 300 in the previous example! What happened? AVG computed the average of the
combined column hits divided by at bats, whereas the example with SUM divided the total number of hits by the
number of at bats. For example, player A gets 50 hits in 100 at bats for a .500 average. Player B gets 0 hits in 1 at
bat for a 0.0 average. The average of 0.0 and 0.5 is .250. If we compute the combined average of 50 hits in 101 at
bats, the answer is a respectable .495. The following statement returns the correct batting average:
SQL> SELECT AVG(HITS)/AVG(AB) TEAM_AVERAGE
FROM TEAMSTATS;
TEAM_AVERAGE
-----------.33706294
Like the SUM function, AVG works only with numbers.

1.4. MAX
If we want to find the largest value in a column, use MAX. For example, what is the highest number of hits?
SQL> SELECT MAX(HITS)
FROM TEAMSTATS;
MAX(HITS)
--------70
Can we find out who has the most hits?
SQL> SELECT NAME
FROM TEAMSTATS
WHERE HITS = MAX(HITS);
***### ERROR at line 3:
ORA-00934: group function is not allowed here
Unfortunately, we can't. The error message is a reminder that this group function ***### (remember that aggregate
functions are also called group functions) doesnt work in WHERE clause.
What happens if we try a non-numerical column?
SQL> SELECT MAX(NAME)
FROM TEAMSTATS;
MAX(NAME)
--------------WORLEY
Here's something new. MAX returns the highest (closest to Z) string. Finally, a function works with both characters and
numbers.

Structure Query Language (SQL)-Functions

Page 44 of 140
WK: 1 - Day: 1.1

1.5. MIN
MIN returns the lowest member of a column. To find out the fewest at bats, type
SQL> SELECT MIN(AB)
FROM TEAMSTATS;
MIN(AB)
--------1
The following statement returns the name closest to the beginning of the alphabet:
SQL> SELECT MIN(NAME)
FROM TEAMSTATS;
MIN(NAME)
--------------CASEY
We can combine MIN with MAX to give a range of values. For example:
SQL> SELECT MIN(AB), MAX(AB)
FROM TEAMSTATS;
MIN(AB) MAX(AB)
-------- -------1
187
This sort of information can be useful when using statistical functions.
NOTE: As we mentioned in the introduction, the first five aggregate functions are described in the ANSI standard.
The remaining aggregate functions have become de facto standards, present in all important implementations of
SQL. We use the Oracle7 names for these functions. Other implementations may use different names.

1.6. VARIANCE
VARIANCE produces square of standard deviation, a number vital to many statistical calculations. It works like this:
SQL> SELECT VARIANCE(HITS)
FROM TEAMSTATS;
VARIANCE(HITS)
-------------802.96667
If we try a string
SQL> SELECT VARIANCE(NAME)
FROM TEAMSTATS;
ERROR:
ORA-01722: invalid number
no rows selected
We find that VARIANCE is another function that works exclusively with numbers.

1.7. STDDEV
Final group function, STDDEV, finds the standard deviation of a column of numbers, as demonstrated by this example:
SQL> SELECT STDDEV(HITS)
FROM TEAMSTATS;
STDDEV(HITS)
-----------28.336666
It also returns an error when confronted by a string:

Structure Query Language (SQL)-Functions

Page 45 of 140
WK: 1 - Day: 1.1

***### SQL> SELECT STDDEV(NAME)


FROM TEAMSTATS;
ERROR:
ORA-01722: invalid number
no rows selected
These aggregate functions can also be used in various combinations:
SQL> SELECT COUNT(AB),AVG(AB),MIN(AB),MAX(AB),STDDEV(AB),VARIANCE(AB),SUM(AB)
FROM TEAMSTATS;
COUNT(AB) AVG(AB) MIN(AB) MAX(AB) STDDEV(AB) VARIANCE(AB) SUM(AB)
--------- ------- ------- ------- ---------- ------------ ------6
119.167
1
187
75.589
5712.97
715
The next time we hear a sportscaster use statistics to fill the time between plays, we will know that SQL is at work
somewhere behind the scenes.

2. Date and Time Functions


We live in a civilization governed by times and dates, and most major implementations of SQL have functions to cope
with these concepts. This section uses the table PROJECT to demonstrate the time and date functions.
SQL> SELECT * FROM PROJECT;
TASK
-------------KICKOFF MTG
TECH SURVEY
USER MTGS
DESIGN WIDGET
CODE WIDGET
TESTING

STARTDATE
--------01-APR-95
02-APR-95
15-MAY-95
01-JUN-95
01-JUL-95
03-SEP-95

ENDDATE
--------01-APR-95
01-MAY-95
30-MAY-95
30-JUN-95
02-SEP-95
17-JAN-96

6 rows selected.
Note: This table used the Date data type. Most implementations of SQL have a Date data type, but the exact syntax
may vary.

2.1. ADD_MONTHS
This function adds a number of months to a specified date. For example, say something extraordinary happened, and
the preceding project slipped to the right by two months. We could make a new schedule by typing
SQL> SELECT TASK, STARTDATE, ENDDATE ORIGINAL_END, ADD_MONTHS(ENDDATE,2)
FROM PROJECT;
TASK
-------------KICKOFF MTG
TECH SURVEY
USER MTGS
DESIGN WIDGET
CODE WIDGET
TESTING

STARTDATE
--------01-APR-95
02-APR-95
15-MAY-95
01-JUN-95
01-JUL-95
03-SEP-95

ORIGINAL_
--------01-APR-95
01-MAY-95
30-MAY-95
30-JUN-95
02-SEP-95
17-JAN-96

ADD_MONTH
--------01-JUN-95
01-JUL-95
30-JUL-95
31-AUG-95
02-NOV-95
17-MAR-96

6 rows selected.
Not that a slip like this is possible, but it's nice to have a function that makes it so easy. ADD_MONTHS also works
outside the SELECT clause. Typing
SQL> SELECT TASK TASKS_SHORTER_THAN_ONE_MONTH
FROM PROJECT
WHERE ADD_MONTHS(STARTDATE,1) > ENDDATE;
TASKS_SHORTER_THAN_ONE_MONTH

Structure Query Language (SQL)-Functions

Page 46 of 140
WK: 1 - Day: 1.1

---------------------------KICKOFF MTG
TECH SURVEY
USER MTGS
DESIGN WIDGET

Analysis:
***### we will find that all the functions in this section work in more than one place. However, ADD MONTHS does
not work with other data types like character or number without the help of functions TO_CHAR and TO_DATE, which
are discussed later today.

2.2. LAST_DAY
LAST_DAY returns the last day of a specified month. It is for those of us who haven't mastered the "Thirty days has
September..." rhyme--or at least those of us who have not yet taught it to our computers. If, for example, we need to
know what the last day of the month is in the column ENDDATE, we would type
SQL> SELECT ENDDATE, LAST_DAY(ENDDATE)
FROM PROJECT;
ENDDATE
LAST_DAY(ENDDATE)
--------- ----------------01-APR-95 30-APR-95
01-MAY-95 31-MAY-95
30-MAY-95 31-MAY-95
30-JUN-95 30-JUN-95
02-SEP-95 30-SEP-95
17-JAN-96 31-JAN-96
6 rows selected.
How does LAST DAY handle leap years?
SQL> SELECT LAST_DAY('1-FEB-95') NON_LEAP,
LAST_DAY('1-FEB-96') LEAP
FROM PROJECT;
NON_LEAP LEAP
--------- --------28-FEB-95 29-FEB-96
28-FEB-95 29-FEB-96
28-FEB-95 29-FEB-96
28-FEB-95 29-FEB-96
28-FEB-95 29-FEB-96
28-FEB-95 29-FEB-96
6 rows selected.

Analysis:
We got the right result, but why were so many rows returned? Because we didn't specify an existing column or any
conditions, the SQL engine applied the date functions in the statement to each existing row. Let's get something less
redundant by using the following:
SQL>SELECT DISTINCT LAST_DAY('1-FEB-95') NON_LEAP,
LAST_DAY('1-FEB-96') LEAP
FROM PROJECT;
This statement uses the word DISTINCT to produce the singular result
NON_LEAP LEAP
--------- --------28-FEB-95 29-FEB-96
Unlike we, this function knows which years are leap years. But before we trust our own or our company's financial
future to this or any other function, check our implementation!

Structure Query Language (SQL)-Functions

Page 47 of 140
WK: 1 - Day: 1.1

2.3. MONTHS_BETWEEN
If we need to know how many months fall between month x and month y, use MONTHS_BETWEEN like this:
SQL> SELECT TASK,STARTDATE,ENDDATE,MONTHS_BETWEEN(STARTDATE,ENDDATE) DURATION
FROM PROJECT;
TASK
STARTDATE
-------------- --------KICKOFF MTG
01-APR-95
TECH SURVEY
02-APR-95
USER MTGS
15-MAY-95
DESIGN WIDGET 01-JUN-95
CODE WIDGET
01-JUL-95
TESTING
03-SEP-95
6 rows selected.

ENDDATE
--------01-APR-95
01-MAY-95
30-MAY-95
30-JUN-95
02-SEP-95
17-JAN-96

DURATION
--------0
-.9677419
-.483871
-.9354839
-2.032258
-4.451613

Wait a minute--that doesn't look right. Try this:


SQL> SELECT TASK, STARTDATE,ENDDATE,MONTHS_BETWEEN(ENDDATE,STARTDATE) DURATION
FROM PROJECT;
TASK
STARTDATE
-------------- --------KICKOFF MTG
01-APR-95
TECH SURVEY
02-APR-95
USER MTGS
15-MAY-95
DESIGN WIDGET 01-JUN-95
CODE WIDGET
01-JUL-95
TESTING
03-SEP-95
6 rows selected.

ENDDATE
--------01-APR-95
01-MAY-95
30-MAY-95
30-JUN-95
02-SEP-95
17-JAN-96

DURATION
--------0
.96774194
.48387097
.93548387
2.0322581
4.4516129

Analysis:
That's better. We see that MONTHS_BETWEEN is sensitive to the way we order the months. Negative months might not
be bad. For example, we could use a negative result to determine whether one date happened before another. For
example, the following statement shows all the tasks that started before May 19, 1995:
SQL> SELECT *
FROM PROJECT
WHERE MONTHS_BETWEEN('19 MAY 95', STARTDATE) > 0;
TASK
-------------KICKOFF MTG
TECH SURVEY
USER MTGS

STARTDATE
--------01-APR-95
02-APR-95
15-MAY-95

ENDDATE
--------01-APR-95
01-MAY-95
30-MAY-95

2.4. NEW_TIME
If we need to adjust the time according to the time zone we are in, the NEW_TIME function is for us. Here are the time
zones we can use with this function:

Abbreviation

Time Zone

AST or ADT

Atlantic standard or daylight time

BST or BDT

Bering standard or daylight time

CST or CDT

Central standard or daylight time

EST or EDT

Eastern standard or daylight time

GMT

Greenwich mean time

HST or HDT

Alaska-Hawaii standard or daylight time

MST or MDT

Mountain standard or daylight time

Structure Query Language (SQL)-Functions

NST

Newfoundland standard time

PST or PDT

Pacific standard or daylight time

YST or YDT

Yukon standard or daylight time

Page 48 of 140
WK: 1 - Day: 1.1

We can adjust our time like this:


SQL> SELECT ENDDATE EDT,
NEW_TIME(ENDDATE, 'EDT','PDT')
FROM PROJECT;
EDT
---------------01-APR-95 1200AM
01-MAY-95 1200AM
30-MAY-95 1200AM
30-JUN-95 1200AM
02-SEP-95 1200AM
17-JAN-96 1200AM
6 rows selected.

NEW_TIME(ENDDATE
---------------31-MAR-95 0900PM
30-APR-95 0900PM
29-MAY-95 0900PM
29-JUN-95 0900PM
01-SEP-95 0900PM
16-JAN-96 0900PM

Like magic, all the times are in the new time zone and the dates are adjusted.

2.5. NEXT_DAY
NEXT_DAY finds the name of the first day of the week that is equal to or later than another specified date. For
example, to send a report on the Friday following the first day of each event, we would type
SQL> SELECT STARTDATE,
NEXT_DAY(STARTDATE, 'FRIDAY')
FROM PROJECT;
STARTDATE NEXT_DAY(
--------- --------01-APR-95 07-APR-95
02-APR-95 07-APR-95
15-MAY-95 19-MAY-95
01-JUN-95 02-JUN-95
01-JUL-95 07-JUL-95
03-SEP-95 08-SEP-95
6 rows selected.

Analysis:
The output tells us the date of the first Friday that occurs after our STARTDATE.

2.6. SYSDATE
SYSDATE returns the system time and date:
SQL> SELECT DISTINCT SYSDATE
FROM PROJECT;
SYSDATE
---------------18-JUN-95 1020PM
If we wanted to see where we stand today in a certain project, we can type
SQL> SELECT *
FROM PROJECT
WHERE STARTDATE > SYSDATE;
TASK
STARTDATE ENDDATE
-------------- --------- --------CODE WIDGET
01-JUL-95 02-SEP-95

Structure Query Language (SQL)-Functions

TESTING

Page 49 of 140
WK: 1 - Day: 1.1

03-SEP-95 17-JAN-96

Now we can see what parts of the project start after today.

3. Arithmetic Functions
Many of the uses we have for the data we retrieve involve mathematics. Most implementations of SQL provide
arithmetic functions similar to the functions covered here. The examples in this section use the NUMCHAR table:
SQL> SELECT *
FROM NUMCHAR;
A
B LASTNAME
--------- -------- --------------3.1415
4 PURVIS
-45
.707 TAYLOR
5
9 CHRISTINE
-57.667
42 ADAMS
15
55 COSTALES
-7.2
5.3 KONG

FIRSTNAME
--------------KELLY
CHUCK
LAURA
FESTER
ARMANDO
MAJOR

M
CODE CHARCODE
- --------- -------A
32 15
J
67 30
C
65 25
M
87 40
A
77 35
G
52 20

6 rows selected.

3.1. ABS
The ABS function returns the absolute value of the number we point to. For example:
SQL> SELECT ABS(A) ABSOLUTE_VALUE
FROM NUMCHAR;
ABSOLUTE_VALUE
-------------3.1415
45
5
57.667
15
7.2
6 rows selected.
ABS changes all the negative numbers to positive and leaves positive numbers alone.

3.2. CEIL and FLOOR


CEIL returns the smallest integer greater than or equal to its argument. FLOOR does just the reverse, returning the
largest integer equal to or less than its argument. For example:
SQL> SELECT B, CEIL(B) CEILING
FROM NUMCHAR;
B
CEILING
--------- --------4
4
.707
1
9
9
42
42
55
55
5.3
6
6 rows selected.
And
SQL> SELECT A, FLOOR(A) FLOOR
FROM NUMCHAR;
A

FLOOR

Structure Query Language (SQL)-Functions

Page 50 of 140
WK: 1 - Day: 1.1

--------- --------3.1415
3
-45
-45
5
5
-57.667
-58
15
15
-7.2
-8
6 rows selected.

3.3. COS, COSH, SIN, SINH, TAN, and TANH


The COS, SIN, and TAN functions provide support for various trigonometric concepts. They all work on the
assumption that n is in radians. The following statement returns some unexpected values if we don't realize COS
expects A to be in radians.
SQL> SELECT A, COS(A)
FROM NUMCHAR;
A
--------3.1415
-45
5
-57.667
15
-7.2

COS(A)
---------1
.52532199
.28366219
.437183
-.7596879
.60835131

Analysis:
We would expect the COS of 45 degrees to be in the neighborhood of .707, not .525. To make this function work the
way we would expect it to in a degree-oriented world, we need to convert degrees to radians. (When was the last
time we heard a news broadcast report that a politician had done a pi-radian turn? We hear about a 180-degree turn.)
Because 360 degrees - 2 pi radians, we can write
SQL> SELECT A, COS(A* 0.01745329251994)
FROM NUMCHAR;
A COS(A*0.01745329251994)
--------- ----------------------3.1415
.99849724
-45
.70710678
5
.9961947
-57.667
.5348391
15
.96592583
-7.2
.9921147

Analysis:
Note that the number 0.01745329251994 is radians divided by degrees. The trigonometric functions work as
follows:
SQL> SELECT A, COS(A*0.017453), COSH(A*0.017453)
FROM NUMCHAR;
A COS(A*0.017453) COSH(A*0.017453)
--------- --------------- ---------------3.1415
.99849729
1.0015035
-45
.70711609
1.3245977
5
.99619483
1.00381
-57.667
.53485335
1.5507072
15
.96592696
1.0344645
-7.2
.99211497
1.0079058
6 rows selected.
And

Structure Query Language (SQL)-Functions

Page 51 of 140
WK: 1 - Day: 1.1

SQL> SELECT A, SIN(A*0.017453), SINH(A*0.017453)


FROM NUMCHAR;
A SIN(A*0.017453) SINH(A*0.017453)
--------- --------------- ---------------3.1415
.05480113
.05485607
-45
-.7070975
-.8686535
5
.08715429
.0873758
-57.667
-.8449449
-1.185197
15
.25881481
.26479569
-7.2
-.1253311
-.1259926
6 rows selected.
And
SQL> SELECT A, TAN(A*0.017453), TANH(A*0.017453)
FROM NUMCHAR;
A TAN(A*0.017453) TANH(A*0.017453)
--------- --------------- ---------------3.1415
.05488361
.05477372
-45
-.9999737
-.6557867
5
.08748719
.08704416
-57.667
-1.579769
-.7642948
15
.26794449
.25597369
-7.2
-.1263272
-.1250043
6 rows selected.

3.4. EXP
EXP enables we to raise e (e is a mathematical constant used in various formulas) to a power. Here's how EXP raises
e by the values in column A:
SQL> SELECT A, EXP(A)
FROM NUMCHAR;
A
EXP(A)
--------- --------3.1415 23.138549
-45 2.863E-20
5 148.41316
-57.667 9.027E-26
15 3269017.4
-7.2 .00074659
6 rows selected.

3.5. LN and LOG


These two functions center on logarithms. LN returns the natural logarithm of its argument. For example:
SQL> SELECT A, LN(A)
FROM NUMCHAR;
ERROR:
ORA-01428: argument '-45' is out of range
Did we neglect to mention that the argument had to be positive? Write
SQL> SELECT A, LN(ABS(A))
FROM NUMCHAR;
A LN(ABS(A))
--------- ---------3.1415 1.1447004
-45 3.8066625
5 1.6094379
-57.667 4.0546851

Structure Query Language (SQL)-Functions

Page 52 of 140
WK: 1 - Day: 1.1

15 2.7080502
-7.2
1.974081
6 rows selected.

Analysis:
Notice how we can embed the function ABS inside the LN call. The other logarith-mic function, LOG, takes two
arguments, returning the logarithm of the first argument in the base of the second. The following query returns the
logarithms of column B in base 10.
SQL> SELECT B, LOG(B, 10)
FROM NUMCHAR;
B LOG(B,10)
----------- --------4 1.660964
.707 -6.640962
9 1.0479516
42 .61604832
55 .57459287
5.3 1.3806894
6 rows selected.

3.6. MOD
We have encountered MOD before. On Day 3, "Expressions, Conditions, and Operators," we saw that the ANSI
standard for the modulo operator % is sometimes implemented as the function MOD. Here's a query that returns a
table showing the remainder of A divided by B:
SQL> SELECT A, B, MOD(A,B)
FROM NUMCHAR;
A
B MOD(A,B)
--------- --------- --------3.1415
4
3.1415
-45
.707
-.459
5
9
5
-57.667
42
-15.667
15
55
15
-7.2
5.3
-1.9
6 rows selected.

3.7. POWER
To raise one number to the power of another, use POWER. In this function the first argument is raised to the power of
the second:
SQL> SELECT A, B, POWER(A,B)
FROM NUMCHAR;
ERROR:
ORA-01428: argument '-45' is out of range

Analysis:
***### At first glance we are likely to think that the first argument can't be negative. But that impression can't be
true, because a number like -4 can be raised to a power. Therefore, if the first number in the POWER function is
negative, the second must be an integer. We can work around this problem by using CEIL (or FLOOR):
SQL> SELECT A, CEIL(B), POWER(A,CEIL(B))
FROM NUMCHAR;
A
CEIL(B) POWER(A,CEIL(B))
--------- --------- ---------------3.1415
4
97.3976

Structure Query Language (SQL)-Functions

-45
1
5
9
-57.667
42
15
55
-7.2
6
6 rows selected.

Page 53 of 140
WK: 1 - Day: 1.1

-45
1953125
9.098E+73
4.842E+64
139314.07

3.8. SIGN
SIGN returns -1 if its argument is less than 0, 0 if its argument is equal to 0, and 1 if its argument is greater than 0,
as shown in the following example:
SQL> SELECT A, SIGN(A)
FROM NUMCHAR;
A
SIGN(A)
--------- --------3.1415
1
-45
-1
5
1
-57.667
-1
15
1
-7.2
-1
0
0
7 rows selected.
We could also use SIGN in a SELECT WHERE clause like this:
SQL> SELECT A
FROM NUMCHAR
WHERE SIGN(A) - 1;
A
--------3.1415
5
15

3.9. SQRT
The function SQRT returns the square root of an argument. Because the square root of a negative number is
undefined, we cannot use SQRT on negative numbers.
SQL> SELECT A, SQRT(A)
FROM NUMCHAR;
ERROR:
ORA-01428: argument '-45' is out of range
However, we can fix this limitation with ABS:
SQL> SELECT ABS(A), SQRT(ABS(A))
FROM NUMCHAR;
ABS(A) SQRT(ABS(A))
--------- -----------3.1415
1.7724277
45
6.7082039
5
2.236068
57.667
7.5938791
15
3.8729833
7.2
2.6832816
0
0
7 rows selected.

Structure Query Language (SQL)-Functions

Page 54 of 140
WK: 1 - Day: 1.1

3.10. ROUND
The ROUND function rounds the column, expression, or value to n decimal places. If the second argument is 0 or is
missing, the value is rounded to zero decimal places. If the second argument is 2, the value is rounded to two
decimal places. Conversely, if the second argument is -2, the value is rounded to two decimal places to the left. The
ROUND function can also be used with DATE function.
SQL> SELECT A, ROUND(A)
FROM NUMCHAR;
A
ROUND(A)
---------- ---------3.1415
3
-45
-45
5
5
-57.667
-58
15
15
-7.2
-7
6 rows selected.
For example if we want to display records with two decimals.
SQL> SELECT A, ROUND(A,2)
FROM NUMCHAR;
A ROUND(A,2)
---------- ---------3.1415
3.14
-45
-45
5
5
-57.667
-57.67
15
15
-7.2
-7.2
6 rows selected.

3.11. TRUNC
The TRUNC function truncates the column, expression, or value to n decimal places. The TRUNC function works with
arguments similar to those of the ROUND function. If the second argument is 0 or is missing, the value is truncated to
zero decimal places. It the second argument is 2, the value is truncated to two decimal places. Conversely, if the
second argument is -2, the value is rounded to two decimal places to the left.
SQL> SELECT A, TRUNC(A)
FROM NUMCHAR;
A
TRUNC(A)
---------- ---------3.1415
3
-45
-45
5
5
-57.667
-57
15
15
-7.2
-7
6 rows selected.
For example if we want to display records with two decimals. This works same as the ROUND function but is doesnt
round the values as ROUND function does.
SQL> SELECT A, TRUNC(A,2)
FROM NUMCHAR;
A TRUNC(A,2)
---------- ----------

Structure Query Language (SQL)-Functions

3.1415
-45
5
-57.667
15
-7.2

Page 55 of 140
WK: 1 - Day: 1.1

3.14
-45
5
-57.66
15
-7.2

6 rows selected.

4. Character Functions
Many implementations of SQL provide functions to manipulate characters and strings of characters. This section
covers the most common character functions. The examples in this section use the table NUMCHAR.

4.1. CHR
CHR returns the character equivalent of the number it uses as argument. The character it returns depends on the
character set of the database. For this example the database is set to ASCII. The column CODE includes numbers.
SQL> SELECT CODE, CHR(CODE)
FROM NUMCHAR;
CODE CH
--------- -32
67 C
65 A
87 W
77 M
52 4
6 rows selected.
The space opposite the 32 shows that 32 is a space in the ASCII character set.

4.2. CONCAT
When we learned about operators. The || symbol splices two strings together, as does CONCAT. It works like this:
SQL> SELECT CONCAT(FIRSTNAME, LASTNAME) "FIRST AND LAST NAMES"
FROM NUMCHAR;
FIRST AND LAST NAMES
-----------------------KELLY
PURVIS
CHUCK
TAYLOR
LAURA
CHRISTINE
FESTER
ADAMS
ARMANDO
COSTALES
MAJOR
KONG
6 rows selected.

Analysis:
Quotation marks surround the multiple-word alias FIRST AND LAST NAMES. Again, it is safest to check our
implementation to see if it allows multiple-word aliases.
Also notice that even though the table looks like two separate columns, what we are seeing is one column. The first
value we concatenated, FIRSTNAME, is 15 characters wide. This operation retained all the characters in the field.

4.3. INITCAP
INITCAP capitalizes the first letter of a word and makes all other characters lowercase.
SQL> SELECT FIRSTNAME BEFORE, INITCAP(FIRSTNAME) AFTER
FROM NUMCHAR;

Structure Query Language (SQL)-Functions

Page 56 of 140
WK: 1 - Day: 1.1

BEFORE
AFTER
-------------- ---------KELLY
Kelly
CHUCK
Chuck
LAURA
Laura
FESTER
Fester
ARMANDO
Armando
MAJOR
Major
6 rows selected.

4.4. LOWER and UPPER


As we might expect, LOWER changes all the characters to lowercase; UPPER does just the reverse.
The following example starts by doing a little magic with the UPDATE function to change one of the values to
lowercase:
SQL> UPDATE NUMCHAR
SET FIRSTNAME = 'kelly'
WHERE FIRSTNAME = 'KELLY';
1 row updated.
SQL> SELECT FIRSTNAME
FROM NUMCHAR;
FIRSTNAME
--------------kelly
CHUCK
LAURA
FESTER
ARMANDO
MAJOR
6 rows selected.
Then we write
SQL> SELECT FIRSTNAME, UPPER(FIRSTNAME), LOWER(FIRSTNAME)
FROM NUMCHAR;
FIRSTNAME
UPPER(FIRSTNAME
--------------- --------------kelly
KELLY
CHUCK
CHUCK
LAURA
LAURA
FESTER
FESTER
ARMANDO
ARMANDO
MAJOR
MAJOR
6 rows selected.

LOWER(FIRSTNAME
--------------kelly
chuck
laura
fester
armando
major

Now we see the desired behavior.

4.5. LPAD and RPAD


LPAD and RPAD take a minimum of two and a maximum of three arguments. The first argument is the character string
to be operated on. The second is the number of characters to pad it with, and the optional third argument is the
character to pad it with. The third argument defaults to a blank or it can be a single character or a character string.
The following statement adds five pad characters, assuming that the field LASTNAME is defined as a 15-character
field:
SQL> SELECT LASTNAME, LPAD(LASTNAME,20,'*')
FROM NUMCHAR;
LASTNAME

LPAD(LASTNAME,20,'*'

Structure Query Language (SQL)-Functions

Page 57 of 140
WK: 1 - Day: 1.1

-------------- -------------------PURVIS
*****PURVIS
TAYLOR
*****TAYLOR
CHRISTINE
*****CHRISTINE
ADAMS
*****ADAMS
COSTALES
*****COSTALES
KONG
*****KONG
6 rows selected.

Analysis:
Why were only five pad characters added? Remember that the LASTNAME column is 15 characters wide and that
LASTNAME includes the blanks to the right of the characters that make up the name. Some column data types
eliminate padding characters if the width of the column value is less than the total width allocated for the column.
Check our implementation. Now try the right side:
SQL> SELECT LASTNAME, RPAD(LASTNAME,20,'*')
FROM NUMCHAR;
LASTNAME
RPAD(LASTNAME,20,'*'
--------------- -------------------PURVIS
PURVIS
*****
TAYLOR
TAYLOR
*****
CHRISTINE
CHRISTINE
*****
ADAMS
ADAMS
*****
COSTALES
COSTALES
*****
KONG
KONG
*****
6 rows selected.

Analysis:
Here we see that the blanks are considered part of the field name for these operations. The next two functions come
in handy in this type of situation.

4.6. LTRIM and RTRIM


LTRIM and RTRIM take at least one and at most two arguments. The first argument, like LPAD and RPAD, is a
character string. The optional second element is either a character or character string or defaults to a blank. If we use
a second argument that is not a blank, these trim functions will trim that character the same way they trim the blanks
in the following examples.
SQL> SELECT LASTNAME, RTRIM(LASTNAME)
FROM NUMCHAR;
LASTNAME
RTRIM(LASTNAME)
--------------- --------------PURVIS
PURVIS
TAYLOR
TAYLOR
CHRISTINE
CHRISTINE
ADAMS
ADAMS
COSTALES
COSTALES
KONG
KONG
6 rows selected.
We can make sure that the characters have been trimmed with the following statement:
SQL> SELECT LASTNAME, RPAD(RTRIM(LASTNAME),20,'*')
FROM NUMCHAR;
LASTNAME
--------------PURVIS
TAYLOR
CHRISTINE
ADAMS
COSTALES

RPAD(RTRIM(LASTNAME)
-------------------PURVIS**************
TAYLOR**************
CHRISTINE***********
ADAMS***************
COSTALES************

Structure Query Language (SQL)-Functions

Page 58 of 140
WK: 1 - Day: 1.1

KONG
KONG****************
6 rows selected.
The output proves that trim is working. Now try LTRIM:
SQL> SELECT LASTNAME, LTRIM(LASTNAME, 'C')
FROM NUMCHAR;
LASTNAME
LTRIM(LASTNAME,
--------------- --------------PURVIS
PURVIS
TAYLOR
TAYLOR
CHRISTINE
HRISTINE
ADAMS
ADAMS
COSTALES
OSTALES
KONG
KONG
6 rows selected.
Note the missing Cs in the third and fifth rows.

4.7. REPLACE
REPLACE does just that. Of its three arguments, the first is the string to be searched. The second is the search key.
The last is the optional replacement string. If the third argument is left out or NULL, each occurrence of the search key
on the string to be searched is removed and is not replaced with anything.
SQL> SELECT LASTNAME, REPLACE(LASTNAME, 'ST') REPLACEMENT
FROM NUMCHAR;
LASTNAME
REPLACEMENT
--------------- --------------PURVIS
PURVIS
TAYLOR
TAYLOR
CHRISTINE
CHRIINE
ADAMS
ADAMS
COSTALES
COALES
KONG
KONG
6 rows selected.
If we have a third argument, it is substituted for each occurrence of the search key in the target string. For example:
SQL> SELECT LASTNAME, REPLACE(LASTNAME, 'ST','**') REPLACEMENT
FROM NUMCHAR;
LASTNAME
REPLACEMENT
--------------- -----------PURVIS
PURVIS
TAYLOR
TAYLOR
CHRISTINE
CHRI**INE
ADAMS
ADAMS
COSTALES
CO**ALES
KONG
KONG
6 rows selected.
If the second argument is NULL, the target string is returned with no changes.
SQL> SELECT LASTNAME, REPLACE(LASTNAME, NULL) REPLACEMENT
FROM NUMCHAR;
LASTNAME
REPLACEMENT
--------------- --------------PURVIS
PURVIS
TAYLOR
TAYLOR
CHRISTINE
CHRISTINE
ADAMS
ADAMS
COSTALES
COSTALES
KONG
KONG
6 rows selected.

Structure Query Language (SQL)-Functions

Page 59 of 140
WK: 1 - Day: 1.1

4.8. SUBSTR
This three-argument function enables we to take a piece out of a target string. The first argument is the target string.
The second argument is the position of the first character to be output. The third argument is the number of
characters to show.
SQL> SELECT FIRSTNAME, SUBSTR(FIRSTNAME,2,3)
FROM NUMCHAR;
FIRSTNAME
SUB
--------------- --kelly
ell
CHUCK
HUC
LAURA
AUR
FESTER
EST
ARMANDO
RMA
MAJOR
AJO
6 rows selected.
If we use a negative number as the second argument, the starting point is determined by counting backwards from
the end, like this:
SQL> SELECT FIRSTNAME, SUBSTR(FIRSTNAME,-13,2)
FROM NUMCHAR;
FIRSTNAME
SU
--------------- -kelly
ll
CHUCK
UC
LAURA
UR
FESTER
ST
ARMANDO
MA
MAJOR
JO
6 rows selected.

Analysis:
Remember the character field FIRSTNAME in this example is 15 characters long. That is why we used a -13 to start
at the third character. Counting back from 15 puts us at the start of the third character, not at the start of the second.
If we don't have a third argument, use the following statement instead:
SQL> SELECT FIRSTNAME, SUBSTR(FIRSTNAME,3)
FROM NUMCHAR;
FIRSTNAME
SUBSTR(FIRSTN
--------------- ------------kelly
lly
CHUCK
UCK
LAURA
URA
FESTER
STER
ARMANDO
MANDO
MAJOR
JOR
6 rows selected.

Analysis:
Reading the results of the preceding output is difficult--Social Security numbers usually have dashes. Now try
something fancy and see whether we like the results:

4. 9. TRANSLATE
The function TRANSLATE takes three arguments: the target string, the FROM string, and the TO string. Elements of the
target string that occur in the FROM string are translated to the corresponding element in the TO string.
SQL> SELECT FIRSTNAME, TRANSLATE(FIRSTNAME
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ

Structure Query Language (SQL)-Functions

Page 60 of 140
WK: 1 - Day: 1.1

'NNNNNNNNNNAAAAAAAAAAAAAAAAAAAAAAAAAA)
FROM NUMCHAR;
FIRSTNAME
--------------kelly
CHUCK
LAURA
FESTER
ARMANDO
MAJOR

TRANSLATE(FIRST
--------------kelly
AAAAA
AAAAA
AAAAAA
AAAAAAA
AAAAA

Notice that the function is case sensitive.

4.10. INSTR
To find out where in a string a particular pattern occurs, use INSTR. Its first argument is the target string. The second
argument is the pattern to match. The third and forth are numbers representing where to start looking and which
match to report. This example returns a number representing the first occurrence of O starting with the second
character:
SQL> SELECT LASTNAME, INSTR(LASTNAME, 'O', 2, 1)
FROM NUMCHAR;
LASTNAME
INSTR(LASTNAME,'O',2,1)
--------------- ----------------------PURVIS
0
TAYLOR
5
CHRISTINE
0
ADAMS
0
COSTALES
2
KONG
2
6 rows selected.

Analysis:
The default for the third and fourth arguments is 1. If the third argument is negative, the search starts at a position
determined from the end of the string, instead of from the beginning.

4.11. LENGTH
LENGTH returns the length of its lone character argument. For example:
SQL> SELECT FIRSTNAME, LENGTH(RTRIM(FIRSTNAME))
FROM NUMCHAR;
FIRSTNAME
LENGTH(RTRIM(FIRSTNAME))
--------------- -----------------------kelly
5
CHUCK
5
LAURA
5
FESTER
6
ARMANDO
7
MAJOR
5
6 rows selected.

Analysis:
Note the use of the RTRIM function. Otherwise, LENGTH would return 15 for every value.

5. Conversion Functions
These three conversion functions provide a handy way of converting one type of data to another. These examples
use the table NUMCHAR.

Structure Query Language (SQL)-Functions

Page 61 of 140
WK: 1 - Day: 1.1

5.1. TO_CHAR
The primary use of TO_CHAR is to convert a number into a character. Different implementations may also use it to
convert other data types, like Date, into a character, or to include different formatting arguments. The next example
illustrates the primary use of TO_CHAR:
SQL> SELECT CODE, TO_CHAR(CODE)
FROM NUMCHAR;
CODE
--------32
67
65
87
77
52

TO_CHAR(CODE)
---------------32
67
65
87
77
52

Not very exciting or convincing. Here's how to verify that the function returned a character string:
SQL> SELECT CODE, LENGTH(TO_CHAR(CODE))
FROM NUMCHAR;
CODE
-----32
67
65
87
77
52

LENGTH(TO_CHAR(CODE))
-----------------------2
2
2
2
2
2

Analysis:
LENGTH of a number would have returned an error. Notice the difference between TO_CHAR and the CHR function
discussed earlier. CHR would have turned this number into a character or a symbol, depending on the character set.

5.2. TO_NUMBER
TO_NUMBER is the companion function to TO_CHAR, and of course, it converts a string into a number. For example:
SQL> SELECT CODE, CODE * TO_NUMBER(CHARCODE)
FROM NUMCHAR;
CODE CODE * TO_NUMBER(CHARCODE)
---- -------------------------32
480
67
2010
65
1625
87
3480
77
2695
52
1040

Analysis:
This test would have returned an error if TO_NUMBER had returned a character.

5.3. TO_DATE
To converts character string to data format for this task we use TO_DATE function.
SQL> SELECT ENAME,HIREDATE
FROM EMP
WHERE HIREDATE = TO_DATE('February 22, 1981','Month dd, YYYY');

Structure Query Language (SQL)-Functions

Page 62 of 140
WK: 1 - Day: 1.1

ENAME
HIREDATE
---------- --------WARD
22-FEB-81

Analysis:
February 22, 1981 is a character string and cant be compared with a Data format column, for this we have to convert
the character string value ('February 22, 1981') into a date format value. This is done by the TO_DATE function as we
have seen in the above example. This test would have returned an error if TO_DATE had returned a character.

5.4 NVL
To convert a null value to an actual value, use NVL function to convert data types like date, character and number.

Data Type

Conversion Example

NUMBER

NVL(number_column,9)

DATE

NVL(date_column,01-JAN-06)

CHAR or VARCHAR2

NVL(character_column,Unavailable)

SQL> SELECT SAL, COMM, SAL+NVL(COMM,0) FROM EMP;


SAL
COMM SAL+NVL(COMM,0)
---------- ---------- --------------800
800
1600
300
1900
1250
500
1750
2975
2975
1250
1400
2650
2850
2850
2450
2450
3000
3000
5000
5000
1500
0
1500
1100
1100
950
950
3000
3000
1300
1300
If we dont use NVL function the result will be as shown in the below example:
SQL> SELECT SAL, SAL+COMM FROM EMP;
SAL
SAL+COMM
---------- ---------800
1600
1900
1250
1750
2975
1250
2650
2850
2450
3000
5000
1500
1500
1100
950
3000
1300

Structure Query Language (SQL)-Functions

Page 63 of 140
WK: 1 - Day: 1.1

5.5. DECODE
The decode function decodes an expression in a way similar to the IF-THEN-ELSE logic used in various languages.
The DECODE function decodes expression after comparing it to each search value. If the expression is same as
search, result is returned.
The syntax for the DECODE function is:
SQL> DECODE(EXPRESSION, SEARCH, RESULT[, SEARCH, RESULT]... [, DEFAULT])
SQL> SELECT ENAME, JOB, SAL,
DECODE(JOB, 'CLERK', SAL*1.1,
'MANAGER', SAL*1.15,
'SALESMAN', SAL*1.20,SAL) "REVISED_SALARY"
FROM EMP;
ENAME
---------SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER

JOB
SAL REVISED_SALARY
--------- ---------- -------------CLERK
800
880
SALESMAN
1600
1920
SALESMAN
1250
1500
MANAGER
2975
3421.25
SALESMAN
1250
1500
MANAGER
2850
3277.5
MANAGER
2450
2817.5
ANALYST
3000
3000
PRESIDENT
5000
5000
SALESMAN
1500
1800
CLERK
1100
1210
CLERK
950
1045
ANALYST
3000
3000
CLERK
1300
1430

14 rows selected.

Analysis:
The above decode statement is equivalent to the following IF-THEN-ELSE statement:
IF JOB = CLERK THEN
SAL = SAL * 1.10;
ELSIF JOB = MANAGER THEN
SAL = SAL * 1.15;
ELSIF JOB = SALESMAN THEN
SAL = SAL * 1.20;
ELSE
SAL = SAL';
END IF;
The DECODE function will compare each JOB value, one by one.

6. Miscellaneous Functions
Here are three miscellaneous functions we may find useful.

6.1. GREATEST and LEAST


These functions find the GREATEST or the LEAST member from a series of expressions. For example:
SQL> SELECT GREATEST('ACCOUNTING', 'RESEARCH','SALES', 'OPERATIONS')
FROM DEPT;
GREATEST
-------SALES
SALES

Structure Query Language (SQL)-Functions

Page 64 of 140
WK: 1 - Day: 1.1

SALES
SALES

Analysis:
Notice GREATEST found the word closest to the end of the alphabet. Notice also a seemingly unnecessary FROM and
three occurrences of SALES. If FROM is missing, we will get an error. Every SELECT needs a FROM. The particular
table used in the FROM has three rows, so the function in the SELECT clause is performed for each of them.
SQL> SELECT LEAST(10, 20, 30, 40)
FROM CONVERT;
LEAST(10, 20, 30, 40)
----------------------10
10
10
10
As we can see, GREATEST and LEAST also work with numbers.

6.2. USER
USER returns the character name of the current user of the database.
SQL> SELECT USER FROM DEPT;
USER
-----------------------------WILSHIRE
WILSHIRE
WILSHIRE
WILSHIRE
There really is only one of us. Again, the echo occurs because of the number of rows in the table. USER is similar to
the date functions explained earlier today. Even though USER is not an actual column in the table, it is selected for
each row that is contained in the table.

Structure Query Language (SQL)-Clauses in SQL


140

Page 65 of
WK: 1 - Day: 1.1

Clauses in SQL





WHERE
ORDER BY
GROUP BY
HAVING

To get a feel for where these functions fit in, examine the general syntax for a SELECT statement:

Syntax:
SELECT [DISTINCT | ALL] { *
| { [schema.]{table | view | snapshot}.*
| expr } [ [AS] c_alias ]
[, { [schema.]{table | view | snapshot}.*
| expr } [ [AS] c_alias ] ] ... }
FROM [schema.]{table | view | snapshot}[@dblink] [t_alias]
[, [schema.]{table | view | snapshot}[@dblink] [t_alias] ] ...
[WHERE condition ]
[GROUP BY expr [, expr] ... [HAVING condition] ]
[{UNION | UNION ALL | INTERSECT | MINUS} SELECT command ]
[ORDER BY {expr|position} [ASC | DESC]
[, {expr|position} [ASC | DESC]] ...]
Note: In my experience with SQL, the ANSI standard is really more of an ANSI "suggestion." The preceding syntax
will generally work with any SQL engine, but we may find some slight variations.

1. WHERE Clause
Using just SELECT and FROM, we are limited to returning every row in a table. For example, using these two key
words on the EMP table, we get all seven rows:
With WHERE in our vocabulary, we can be more selective. To find all the employees we wrote with a value of more
than 2000 salary, write this:
SQL> SELECT *
FROM EMP
WHERE SAL > 2000;
The WHERE clause returns the six instances in the table that meets the required condition:
EMPNO
----7566
7698
7782
7788
7839
7902

ENAME
-------JONES
BLAKE
CLARK
SCOTT
KING
FORD

JOB
--------MANAGER
MANAGER
MANAGER
ANALYST
PRESIDENT
ANALYST

MGR
---7839
7839
7839
7566
7566

HIREDATE
--------02-APR-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
03-DEC-81

SAL
---2975
2850
2450
3000
5000
3000

COMM DEPTNO
----- -----20
30
10
20
10
20

WHERE can also be given on the following table with a string condition, we can ask question that, Where's SMITH?
SQL> SELECT EMPNO AS "WHERE'S SMITH?"
FROM EMP
WHERE ENAME = 'SMITH';
WHERE'S SMITH?
-------------7369
This query shows that the column used in the condition of the WHERE statement does not have to be mentioned in the
SELECT clause. In this example we selected the empno column but used WHERE on the name, which is perfectly
legal. Also notice the AS on the SELECT line. AS is an optional assignment operator, assigning the alias WHERE'S
SMITH? to EMPNO. We might never see AS again, because it involves extra typing.
SQL> SELECT EMPNO "WHERE'S SMITH?"

Structure Query Language (SQL)-Clauses in SQL


140

Page 66 of
WK: 1 - Day: 1.1

FROM EMP
WHERE ENAME = 'SMITH';
And get the same result as the previous query without using AS:
WHERE'S SMITH?
-------------7369
After SELECT and FROM, WHERE is the third most frequently used SQL term.

2. ORDER BY Clause
From time to time we presented the results of our query in some kind of order. As we know, however, SELECT FROM
gives us a listing, and unless we have defined a primary key, our query comes out in the order we entered. Consider
a beefed-up CHECKS table:
The ORDER BY clause gives us a way of ordering our results. For example, to order the preceding listing by EMPNO,
we would use the following ORDER BY clause:
SQL> SELECT *
FROM EMP
ORDER BY EMPNO;
EMPNO
----7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934

ENAME
-------SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER

JOB
--------CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK

MGR
---7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782

HIREDATE
--------17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82

SAL
---800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300

COMM DEPTNO
----- -----20
300
30
500
30
20
1400
30
30
10
20
10
0
30
20
30
20
10

14 rows selected.
Now the data is ordered the way we want it, not the way in which it was entered. As the following example shows,
ORDER requires BY; BY is not optional.
SQL> SELECT * FROM EMP ORDER EMPNO;
SELECT * FROM EMP ORDER EMPNO
*
ERROR at line 1:
ORA-00924: missing BY keyword
What if we want to list the data in reverse order, with the highest number or letter first? We're in luck! The following
query generates a list of EMPLOYEES that stars at the end of the alphabet:
SQL> SELECT *
FROM EMP
ORDER BY ENAME DESC;
EMPNO
----7521
7844
7369
7788
7934

ENAME
-------WARD
TURNER
SMITH
SCOTT
MILLER

JOB
--------SALESMAN
SALESMAN
CLERK
ANALYST
CLERK

MGR
---7698
7698
7902
7566
7782

HIREDATE
--------22-FEB-81
08-SEP-81
17-DEC-80
19-APR-87
23-JAN-82

SAL
---1250
1500
800
3000
1300

COMM DEPTNO
----- -----500
30
0
30
20
20
10

Structure Query Language (SQL)-Clauses in SQL


140

Page 67 of
WK: 1 - Day: 1.1

7654
7839
7566
7900
7902
7782
7698
7499
7876

MARTIN
KING
JONES
JAMES
FORD
CLARK
BLAKE
ALLEN
ADAMS

SALESMAN
PRESIDENT
MANAGER
CLERK
ANALYST
MANAGER
MANAGER
SALESMAN
CLERK

7698
7839
7698
7566
7839
7839
7698
7788

28-SEP-81
17-NOV-81
02-APR-81
03-DEC-81
03-DEC-81
09-JUN-81
01-MAY-81
20-FEB-81
23-MAY-87

1250
5000
2975
950
3000
2450
2850
1600
1100

1400

300

30
10
20
30
20
10
30
30
20

14 rows selected.

Analysis:
The DESC at the end of the ORDER BY clause orders the list in descending order instead of the default (ascending)
order. The rarely used, optional keyword ASC appears in the following statement:
SQL> SELECT ENAME, HIREDATE
FROM EMP
ORDER BY EMPNO ASC;
4
---------- ---------SMITH
17-DEC-80
ALLEN
20-FEB-81
WARD
22-FEB-81
JONES
02-APR-81
MARTIN
28-SEP-81
BLAKE
01-MAY-81
CLARK
09-JUN-81
SCOTT
19-APR-87
KING
17-NOV-81
TURNER
08-SEP-81
ADAMS
23-MAY-87
JAMES
03-DEC-81
FORD
03-DEC-81
MILLER
23-JAN-82
14 rows selected.

Analysis:
The ordering in this list is identical to the ordering of the list at the beginning of the section (without ASC) because ASC
is the default. This query also shows that the expression used after the ORDER BY clause does not have to be in the
SELECT statement. Although we selected only ENAME and HIREDATE, we were still able to order the list by EMP.
We can also use ORDER BY on more than one field. To order EMP by ENAME and HIREDATE, the query as follows:
SQL> SELECT *
FROM EMP
ORDER BY ENAME, HIREDATE;
EMPNO
----7876
7499
7698
7782
7902
7900
7566
7839
7654
7934
7788
7369

ENAME
-------ADAMS
ALLEN
BLAKE
CLARK
FORD
JAMES
JONES
KING
MARTIN
MILLER
SCOTT
SMITH

JOB
--------CLERK
SALESMAN
MANAGER
MANAGER
ANALYST
CLERK
MANAGER
PRESIDENT
SALESMAN
CLERK
ANALYST
CLERK

MGR
---7788
7698
7839
7839
7566
7698
7839
7698
7782
7566
7902

HIREDATE
--------23-MAY-87
20-FEB-81
01-MAY-81
09-JUN-81
03-DEC-81
03-DEC-81
02-APR-81
17-NOV-81
28-SEP-81
23-JAN-82
19-APR-87
17-DEC-80

SAL
---1100
1600
2850
2450
3000
950
2975
5000
1250
1300
3000
800

COMM DEPTNO
----- -----20
300
30
30
10
20
30
20
10
1400
30
10
20
20

Structure Query Language (SQL)-Clauses in SQL


140

Page 68 of
WK: 1 - Day: 1.1

7844
7521

TURNER
WARD

SALESMAN
SALESMAN

7698 08-SEP-81
7698 22-FEB-81

1500
1250

0
500

30
30

14 rows selected.

Analysis:
In the previous ORDER BY, the EMP was in the order 7876 to 7521. Adding the field HIREDATE to the ORDER BY
clause puts the entries in alphabetical order according to HIREDATE. Does the order of multiple columns in the
ORDER BY clause make a difference? Try the same query again but reverse ENAME and HIREDATE:
SQL> SELECT *
FROM EMP
ORDER BY HIREDATE, ENAME;
EMPNO
----7369
7499
7521
7566
7698
7782
7844
7654
7839
7902
7900
7934
7788
7876

ENAME
-------SMITH
ALLEN
WARD
JONES
BLAKE
CLARK
TURNER
MARTIN
KING
FORD
JAMES
MILLER
SCOTT
ADAMS

JOB
--------CLERK
SALESMAN
SALESMAN
MANAGER
MANAGER
MANAGER
SALESMAN
SALESMAN
PRESIDENT
ANALYST
CLERK
CLERK
ANALYST
CLERK

MGR
---7902
7698
7698
7839
7839
7839
7698
7698
7566
7698
7782
7566
7788

HIREDATE
--------17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
01-MAY-81
09-JUN-81
08-SEP-81
28-SEP-81
17-NOV-81
03-DEC-81
03-DEC-81
23-JAN-82
19-APR-87
23-MAY-87

SAL
---800
1600
1250
2975
2850
2450
1500
1250
5000
3000
950
1300
3000
1100

COMM DEPTNO
----- -----20
300
30
500
30
20
30
10
0
30
1400
30
10
20
30
10
20
20

14 rows selected.

Analysis:
As we probably guessed, the results are completely different. Here's how to list one column in alphabetical order and
list the second column is not in alphabetical order:
SQL> SELECT *
FROM EMP
ORDER BY ENAME ASC, HIREDATE DESC;
EMPNO
----7876
7499
7698
7782
7902
7900
7566
7839
7654
7934
7788
7369
7844
7521

ENAME
-------ADAMS
ALLEN
BLAKE
CLARK
FORD
JAMES
JONES
KING
MARTIN
MILLER
SCOTT
SMITH
TURNER
WARD

JOB
--------CLERK
SALESMAN
MANAGER
MANAGER
ANALYST
CLERK
MANAGER
PRESIDENT
SALESMAN
CLERK
ANALYST
CLERK
SALESMAN
SALESMAN

MGR
---7788
7698
7839
7839
7566
7698
7839
7698
7782
7566
7902
7698
7698

HIREDATE
--------23-MAY-87
20-FEB-81
01-MAY-81
09-JUN-81
03-DEC-81
03-DEC-81
02-APR-81
17-NOV-81
28-SEP-81
23-JAN-82
19-APR-87
17-DEC-80
08-SEP-81
22-FEB-81

SAL
---1100
1600
2850
2450
3000
950
2975
5000
1250
1300
3000
800
1500
1250

COMM DEPTNO
----- -----20
300
30
30
10
20
30
20
10
1400
30
10
20
20
0
30
500
30

14 rows selected.

Analysis:
In this example ENAME is sorted alphabetically, and HIREDATE appears in descending order.

Structure Query Language (SQL)-Clauses in SQL


140

Page 69 of
WK: 1 - Day: 1.1

Tip: If we know that a column we want to order our results by is the first column in a table, then we can type ORDER
BY 1 in place of spelling out the column name. See the following example.
SQL> SELECT *
FROM EMP
ORDER BY 1;
EMPNO
----7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934

ENAME
-------SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER

JOB
--------CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK

MGR
---7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782

HIREDATE
--------17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82

SAL
---800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300

COMM DEPTNO
----- -----20
300
30
500
30
20
1400
30
30
10
20
10
0
30
20
30
20
10

14 rows selected.

Analysis:
This result is identical to the result produced by the SELECT statement that we used earlier today:
SQL> SELECT * FROM EMP ORDER BY EMPNO;

4. GROUP BY Clause
How to use aggregate functions (COUNT, SUM, AVG, MIN, and MAX). If we wanted to find the total amount of money
spent on EMP table, we would type:
Then we would type:
SQL> SELECT SUM(SAL)
FROM EMP;
SUM
--------------29025

Analysis:
This statement returns the sum of the column SAL. What if we wanted to find out how much we have spent on each
EMPNO? SQL helps us with the GROUP BY clause. To find out whom we have paid and how much, we would query
like this:
SQL> SELECT DEPTNO, SUM(SAL)
FROM EMP
GROUP BY DEPTNO;
DEPTNO
SUM(SAL)
---------- ---------10
8750
20
10875
30
9400

Analysis:
The SELECT clause has a normal column selection, DEPTNO, followed by the aggregate function SUM(AMOUNT). If we
had tried this query with only the FROM EMP that follows, here's what we would see:

Structure Query Language (SQL)-Clauses in SQL


140

Page 70 of
WK: 1 - Day: 1.1

SQL> SELECT DEPTNO, SUM(SAL)


FROM EMP;
Dynamic SQL Error
-SQL error code - -104
-invalid column reference

Analysis:
SQL is complaining about combination of the normal column and the aggregate function. This condition requires the
GROUP BY clause. GROUP BY runs the aggregate function described in the SELECT statement for each grouping of
the column that follows the GROUP BY clause. The table EMP returned 14 rows when queried with SELECT * FROM
EMP. The query on the same table, SELECT DEPTNO, SUM(SAL) FROM EMP GROUP BY DEPTNO, took the 14
rows in the table and made 3 groupings, returning the SUM of each grouping. Suppose we wanted to know how many
employees are working under which Manager along with total salary. Can we use more than one aggregate function?
SQL> SELECT MGR, SUM(SAL), COUNT(EMPNO)
FROM EMP
GROUP BY MGR;
MGR
SUM(SAL) COUNT(EMPNO)
---------- ---------- -----------7566
6000
2
7698
6550
5
7782
1300
1
7788
1100
1
7839
8275
3
7902
800
1
5000
1
7 rows selected.

Analysis:
This SQL is becoming increasingly useful. In the preceding example, we were able to perform group functions on
unique groups using the GROUP BY clause. Also notice that the results were ordered by MGR. GROUP BY also acts
like the ORDER BY clause. What would happen if we tried to group by more than one column? Try this:
SQL> SELECT MGR, SUM(SAL), COUNT(EMPNO)
FROM EMP
GROUP BY MGR, DEPTNO;
MGR
SUM(SAL) COUNT(EMPNO)
---------- ---------- -----------5000
1
7566
6000
2
7698
6550
5
7782
1300
1
7788
1100
1
7839
2450
1
7839
2975
1
7839
2850
1
7902
800
1
9 rows selected.

Analysis:
The output has gone from 3 groupings of 14 rows to 9 groupings. What is different about the one grouping with more
than one Employee associated with it? Look at the entries for MGR:
SQL> SELECT MGR, DEPTNO
FROM EMP
WHERE MGR = 7698;

Structure Query Language (SQL)-Clauses in SQL


140

Page 71 of
WK: 1 - Day: 1.1

MGR
DEPTNO
---------- ---------7698
30
7698
30
7698
30
7698
30
7698
30

Analysis:
We see that the combination of MGR and DEPTNO creates identical entities, which SQL groups together into one line
with the GROUP BY clause. The other rows produce unique combinations of MGR and DEPTNO and are assigned their
own unique groupings. The next example finds the largest and smallest salaries, grouped by DEPTNO:
SQL> SELECT MIN(SAL), MAX(SAL)
FROM EMP
GROUP BY DEPTNO;
MIN(SAL)
MAX(SAL)
---------- ---------1300
5000
800
3000
950
2850
Here's what will happen if we try to include in the SELECT statement a column that has several different values within
the group formed by GROUP BY:
SQL> SELECT MGR, MAX(SAL), MIN(SAL)
FROM EMP
GROUP BY DEPTNO;
select mgr,min(sal),max(sal) from emp group by deptno
*
ERROR at line 1:
ORA-00979: not a GROUP BY expression

Analysis:
This query tries to group EMP by DEPTNO. When the query finds two records with the same DEPTNO but different
MGRs, such as the rows that have 30 as a DEPTNO but have MGRs of LOCAL UTILITIES and 30, it throws an error.
The rule is, don't use the SELECT statement on columns that have multiple values for the GROUP BY clause column.
The reverse is not true. We can use GROUP BY on columns not mentioned in the SELECT statement. For example:
SQL> SELECT MGR, COUNT(SAL)
FROM EMP
GROUP BY MGR, SAL;
MGR COUNT(SAL)
---------- ---------1
7566
2
7698
1
7698
1
7698
1
7698
2
7782
1
7788
1
7839
1
7839
1
7839
1
7902
1
12 rows selected.

Analysis:

Structure Query Language (SQL)-Clauses in SQL


140

Page 72 of
WK: 1 - Day: 1.1

This simple query shows how many EMP have identical amounts to the same MGR. Its real purpose is to show that we
can use SAL in the GROUP BY clause, even though it is not mentioned in the SELECT clause. Try moving SAL out of
the GROUP BY clause and into the SELECT clause, like this:
SQL> SELECT MGR, SAL, COUNT(SAL)
FROM EMP
GROUP BY MGR;
select mgr,sal,count(sal) from emp group by mgr
*
ERROR at line 1:
ORA-00979: not a GROUP BY expression

Analysis:
SQL cannot run the query, which makes sense if we play the part of SQL for a moment. Say we had to group the
following lines:
SQL> SELECT MGR, SAL, ENAME
FROM EMP
WHERE MGR = 7698;
MGR
SAL ENAME
---------- ---------- ---------7698
1600 ALLEN
7698
1250 WARD
7698
1250 MARTIN
7698
1500 TURNER
7698
950 JAMES
If the user asked we to output all 3 columns and group by MGR only, where would we put the unique ENAME?
Remember we have only one row per group when we use GROUP BY. SQL can't do two things at once, so it
complains: Error #31: Can't do two things at once.

5. HAVING Clause
How can we qualify the data used in our GROUP BY clause? Use the same table EMP and try this:
If we wanted to group the output into divisions and show the average salary in each division, we would type:
SQL> SELECT DEPTNO, AVG(SAL)
FROM EMP
GROUP BY DEPTNO;
DEPTNO
AVG(SAL)
---------- ---------10 2916.66667
20
2175
30 1566.66667
The following statement qualifies this query to return only those departments with average salaries under 2500:
SQL> SELECT DEPTNO, AVG(SAL)
FROM EMP
WHERE AVG(SAL) < 2500
GROUP BY DEPTNO;
SELECT DEPTNO,AVG(SAL) FROM EMP WHERE AVG(SAL) < 2500 GROUP BY DEPTNO
*
ERROR at line 1:
ORA-00934: group function is not allowed here

Analysis:
This error occurred because WHERE does not work with aggregate functions. To make this query work, we need
HAVING clause. If we type the following query, we get what we ask for:

Structure Query Language (SQL)-Clauses in SQL


140

Page 73 of
WK: 1 - Day: 1.1

SQL> SELECT DEPTNO, AVG(SAL)


FROM EMP
GROUP BY DEPTNO
HAVING AVG(SAL) < 2500;
DEPTNO
AVG(SAL)
---------- ---------20
2175
30 1566.66667

Analysis:
HAVING enables us to use aggregate functions in a comparison statement, providing for aggregate functions what
WHERE provides for individual rows. Does HAVING works with non-aggregate expressions? Try this:
SQL> SELECT DEPTNO, AVG(SAL),SAL
FROM EMP
GROUP BY DEPTNO, SAL
HAVING SAL < 2500;
DEPTNO
AVG(SAL)
SAL
---------- ---------- ---------10
1300
1300
10
2450
2450
20
800
800
20
1100
1100
30
1500
1500
30
1600
1600
30
950
950
30
1250
1250
8 rows selected.

Analysis:
Why is this result different from last query? HAVING AVG(SAL) < 2500 clause evaluated each grouping and
returned only those with an average salary of under 2500, just what we expected. HAVING SAL < 2500, on other
hand, had a different outcome. If the user asks us to evaluate and return groups of divisions where SAL < 2500, we
would examine each group and reject those where an individual SAL is greater than 2500.
Can we use more than one condition in our HAVING clause? Try this:
SQL> SELECT DEPTNO, AVG(SAL),AVG(COMM)
FROM EMP
GROUP BY DEPTNO
HAVING AVG(SAL)<2500 AND AVG(COMM)<1000;
DEPTNO
AVG(SAL) AVG(COMM)
---------- ---------- ---------30 1566.66667
550

Analysis:
The following table is grouped by DEPTNO. It shows all the teams with SAL averages below 2500 and COMM averages
below 1000.
We can also use an aggregate function in the HAVING clause that was not in the SELECT statement. For example:
SQL> SELECT DEPTNO, AVG(SAL),AVG(COMM)
FROM EMP
GROUP BY DEPTNO
HAVING COUNT(DEPTNO) > 3;
DEPTNO
AVG(SAL) AVG(COMM)
---------- ---------- ---------20
2175

Structure Query Language (SQL)-Clauses in SQL


140

Page 74 of
WK: 1 - Day: 1.1

30 1566.66667

550

Analysis:
This query returns the number of DEPTNOs with more than 3 departments. COUNT(DEPTNO) is not used in the
SELECT statement but still functions as expected in the HAVING clause.
The other logical operators all work well within the HAVING clause. Consider this:
SQL> SELECT DEPTNO,MIN(SAL),MAX(SAL)
FROM EMP
GROUP BY DEPTNO
HAVING AVG(SAL) > 500 OR MIN(SAL) > 500;
DEPTNO
MIN(SAL)
MAX(SAL)
---------- ---------- ---------10
1300
5000
20
800
3000
30
950
2850
The operator IN also works in a HAVING clause, as demonstrated here:
SQL> SELECT DEPTNO,AVG(SAL)
FROM EMP
GROUP BY DEPTNO
HAVING DEPTNO IN (10,30);
DEPTNO
AVG(SAL)
---------- ---------10 2916.66667
30 1566.66667
Always follow a select with aggregate function with a group clause. We can order by a column which is not in the
select clause but we cannot forget the term in SELECT clause in the ORDER BY clause. So also we need to have a
GROUP BY clause when we specify an aggregate function in the SELECT clause otherwise it throws an error. We
can avoid this by putting a where on 1 select attribute and a GROUP BY or ORDER BY on the other.

6. Combining Clauses
Through some composite we demonstrate how combinations of clauses perform together.

Example 6.1
Find all the employees written for MGR and DEPT in the EMP table and order them by ENAME.
SQL> SELECT MGR, ENAME
FROM EMP
WHERE MGR = 7698 OR ENAME LIKE 'A%' ORDER BY ENAME;
MGR
---------7788
7698
7698
7698
7698
7698

ENAME
---------ADAMS
ALLEN
JAMES
MARTIN
TURNER
WARD

6 rows selected.

Analysis:
Note the use of LIKE to find the ENAME that started with A. With the use of OR, data was returned if the WHERE clause
met either one of the two conditions. What if we asked for the same information and group it by MGR? The query
would look something like this:
SQL> SELECT MGR, ENAME

Structure Query Language (SQL)-Clauses in SQL


140

Page 75 of
WK: 1 - Day: 1.1

FROM EMP
WHERE MGR = 7698 OR ENAME LIKE 'A%' GROUP BY MGR ORDER BY ENAME;

Analysis:
This query would not work because the SQL engine would not know what to do with the remarks. Remember that
whatever columns we put in the SELECT clause must also be in the GROUP BY clause--unless we don't specify any
columns in the SELECT clause.

Example 6.2
Using the table EMP, find the salary of everyone with less than 2500. Order the results by ENAME.
SQL> SELECT ENAME, SAL
FROM EMP
WHERE SAL < 2500 ORDER BY ENAME;
ENAME
SAL
---------- ---------ADAMS
1100
ALLEN
1600
CLARK
2450
JAMES
950
MARTIN
1250
MILLER
1300
SMITH
800
TURNER
1500
WARD
1250
9 rows selected.

Analysis:
This query is straight forward and enables us to use our new found skills with WHERE and ORDER BY.

Example 6.3
Again, using EMP, display DEPTNO, AVG(SAL) and AVG(COMM) on each DEPTNO:
SQL> SELECT DEPTNO,AVG(SAL),AVG(COMM)
FROM EMP GROUP BY DEPTNO;
DEPTNO
AVG(SAL) AVG(COMM)
---------- ---------- ---------10 2916.66667
20
2175
30 1566.66667
550

Example 6.4: The Big Finale


Is it possible to use everything we have learned in one query? It is, but the results will be convoluted because in
many ways we are working with apples and oranges--or aggregates and nonaggregates. For example, WHERE and
ORDER BY is usually found in queries that act on single rows, such as this:
SQL> SELECT *
FROM EMP
ORDER BY ENAME DESC;
EMPNO
----7521
7844
7369
7788
7934

ENAME
-------WARD
TURNER
SMITH
SCOTT
MILLER

JOB
--------SALESMAN
SALESMAN
CLERK
ANALYST
CLERK

MGR
---7698
7698
7902
7566
7782

HIREDATE
--------22-FEB-81
08-SEP-81
17-DEC-80
19-APR-87
23-JAN-82

SAL
---1250
1500
800
3000
1300

COMM DEPTNO
----- -----500
30
0
30
20
20
10

Structure Query Language (SQL)-Clauses in SQL


140

Page 76 of
WK: 1 - Day: 1.1

7654
7839
7566
7900
7902
7782
7698
7499
7876

MARTIN
KING
JONES
JAMES
FORD
CLARK
BLAKE
ALLEN
ADAMS

SALESMAN
PRESIDENT
MANAGER
CLERK
ANALYST
MANAGER
MANAGER
SALESMAN
CLERK

7698
7839
7698
7566
7839
7839
7698
7788

28-SEP-81
17-NOV-81
02-APR-81
03-DEC-81
03-DEC-81
09-JUN-81
01-MAY-81
20-FEB-81
23-MAY-87

1250
5000
2975
950
3000
2450
2850
1600
1100

1400

300

30
10
20
30
20
10
30
30
20

GROUP BY and HAVING are normally seen in the company of aggregates:


SQL> SELECT MGR,SUM(SAL) TOTAL,COUNT(EMPNO) NUMBER_WRITTEN
FROM EMP GROUP BY MGR HAVING SUM(SAL) < 2500;
MGR
TOTAL NUMBER_WRITTEN
---------- ---------- -------------7782
1300
1
7788
1100
1
7902
800
1
We have seen that combining these two groups of clauses can have unexpected results, including the following:
SQL> SELECT MGR,SUM(SAL) TOTAL,COUNT(EMPNO) NUMBER_WRITTEN
FROM EMP
WHERE SAL >= 500 GROUP BY MGR HAVING SUM(SAL) < 2500;
MGR
TOTAL NUMBER_WRITTEN
---------- ---------- -------------7782
1300
1
7788
1100
1
7902
800
1
Compare these two result sets and examine the raw data:
SQL> SELECT MGR, SAL
FROM EMP
ORDER BY MGR;
MGR
SAL
---------- ---------7566
3000
7566
3000
7698
1600
7698
1250
7698
950
7698
1500
7698
1250
7782
1300
7788
1100
7839
2975
7839
2450
7839
2850
7902
800
5000
14 rows selected.

Analysis:
We see how WHERE clause filtered out all employees less than 500 before the GROUP BY was performed on the
query. We are not trying to tell we not to mix these groups--we may have a requirement that this sort of construction
will meet. However, we should not casually mix aggregate and non-aggregate functions.

Structure Query Language (SQL)-joins

Page 77 of 140
WK: 1 - Day: 1.1

Joins
This information will enable us to gather and manipulate data across several tables. We will understand and be able
to do the following:








Perform an outer join


Perform a left join
Perform a right join
Perform an equi-join
Perform a non-equi-join
Join a table to itself

1. Introduction
One of the most powerful features of SQL is its capability to gather and manipulate data from across several tables.
Without this feature we would have to store all the data elements necessary for each application in one table. Without
common tables we would need to store the same data in several tables. Imagine having to redesign, rebuild, and
repopulate our tables and databases every time our user needed a query with a new piece of information. The JOIN
statement of SQL enables us to design smaller, more specific tables that are easier to maintain than larger tables.

Multiple Tables in a Single SELECT Statement


The SELECT Statement," when we learned about SELECT and FROM. Use the following two tables, named, cleverly
enough, EMP and DEPT.
NOTE: The queries in today's examples were produced using Borland's ISQL tool. We will notice some differences
between these queries and the ones that we used earlier in the book. For example, these queries do not begin with
an SQL prompt. Another difference is that ISQL does not require a semicolon at the end of the statement. (The
semicolon is optional in ISQL.) But the SQL basics are still the same.
SQL> SELECT *
FROM EMP
EMPNO
----7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934

ENAME
-------SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER

JOB
--------CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK

MGR
---7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782

HIREDATE
--------17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82

SQL> SELECT *
FROM DEPT
DEPTNO
-----10
20
30
40

DNAME
-------------ACCOUNTING
RESEARCH
SALES
OPERATIONS

To join these two tables, type this:


Select * from emp,dept

LOC
------------NEW YORK
DALLAS
CHICAGO
BOSTON

SAL
---800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300

COMM DEPTNO
----- -----20
300
30
500
30
20
1400
30
30
10
20
10
0
30
20
30
20
10

Structure Query Language (SQL)-joins

EMPNO
----7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934
7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934
7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934
7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934

ENAME
----SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER

JOB
--------CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK
CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK
CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK
CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK

MGR
---7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782
7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782
7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782
7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782

Page 78 of 140
WK: 1 - Day: 1.1

HIREDATE
--------17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82
17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82
17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82
17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82

SAL
---800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300
800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300
800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300
800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300

COMM DEPTNO DEPTNO


---- ------ -----20
10
300
30
10
500
30
10
20
10
1400
30
10
30
10
10
10
20
10
10
10
0
30
10
20
10
30
10
20
10
10
10
20
20
300
30
20
500
30
20
20
20
1400
30
20
30
20
10
20
20
20
10
20
0
30
20
20
20
30
20
20
20
10
20
20
30
300
30
30
500
30
30
20
30
1400
30
30
30
30
10
30
20
30
10
30
0
30
30
20
30
30
30
20
30
10
30
20
40
300
30
40
500
30
40
20
40
1400
30
40
30
40
10
40
20
40
10
40
0
30
40
20
40
30
40
20
40
10
40

56 rows selected.
Fifty-six rows! Where did they come from? And what kind of join is this?

Analysis:

DNAME
---------ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS

LOC
-------NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON

Structure Query Language (SQL)-joins

Page 79 of 140
WK: 1 - Day: 1.1

A close examination of the result of our first join shows that each row from EMP was added to each row from DEPT.
An extract from this join shows what happened:
EMPNO
----7369
7369
7369
7369
...

ENAME
----SMITH
SMITH
SMITH
SMITH

JOB
--------CLERK
CLERK
CLERK
CLERK

MGR
---7902
7902
7902
7902

HIREDATE
--------17-DEC-80
17-DEC-80
17-DEC-80
17-DEC-80

SAL
---800
800
800
800

COMM DEPTNO DEPTNO


---- ------ -----20
10
20
20
20
30
20
40

DNAME
---------ACCOUNTING
RESEARCH
SALES
OPERATIONS

LOC
-------NEW YORK
DALLAS
CHICAGO
BOSTON

Notice how each row in DEPT was combined with row 1 in EMP. Congratulations! We have performed our first join.
But what kind of join? An inner join? an outer join? or what? Well, actually this type of join is called a cross-join. A
cross-join is not normally as useful as the other joins covered today, but this join does illustrate the basic combining
property of all joins: Joins bring tables together.
Suppose we sold parts to bike shops for a living. When we designed our database, we built one big table with all the
pertinent columns. Every time we had a new requirement, we added a new column or started a new table with all the
old data plus the new data required to create a specific query. Eventually, our database would collapse from its own
weight-not a pretty sight. An alternative design, based on a relational model, would have we put all related data into
one table. Here's how our customer table would look:
SQL> SELECT * FROM CUSTOMER;
NAME
---------TRUE WHEEL
BIKE SPEC
LE SHOPPE
AAA BIKE
JACKS BIKE

ADDRESS
---------55O HUSKER
CPT SHRIVE
HOMETOWN
10 OLDTOWN
24 EGLIN

STATE
-----NE
LA
KS
NE
FL

ZIP
---------58702
45678
54678
56784
34567

PHONE
REMARKS
--------- ---------555-4545
NONE
555-1234
NONE
555-1278
NONE
555-3421
JOHN-MGR
555-2314
NONE

Analysis:
This table contains all information we need to describe our customers. The items we sold would go into another table:
SQL> SELECT * FROM PART;
PARTNUM
----------54
42
46
23
76
10

DESCRIPTION
PRICE
-------------------- ----------PEDALS
54.25
SEATS
24.50
TIRES
15.25
MOUNTAIN BIKE
350.45
ROAD BIKE
530.00
TANDEM
1200.00

And the orders we take would have their own table:


SQL> SELECT * FROM ORDERS;
ORDEREDON
----------15-MAY-1996
19-MAY-1996
2-SEP-1996
30-JUN-1996
30-JUN-1996
30-MAY-1996
30-MAY-1996
17-JAN-1996
17-JAN-1996
1-JUN-1996
1-JUN-1996
1-JUL-1996
1-JUL-1996
11-JUL-1996

NAME
PARTNUM
QUANTITY REMARKS
---------- ----------- ----------- ------TRUE WHEEL
23
6 PAID
TRUE WHEEL
76
3 PAID
TRUE WHEEL
10
1 PAID
TRUE WHEEL
42
8 PAID
BIKE SPEC
54
10 PAID
BIKE SPEC
10
2 PAID
BIKE SPEC
23
8 PAID
BIKE SPEC
76
11 PAID
LE SHOPPE
76
5 PAID
LE SHOPPE
10
3 PAID
AAA BIKE
10
1 PAID
AAA BIKE
76
4 PAID
AAA BIKE
46
14 PAID
JACKS BIKE
76
14 PAID

Structure Query Language (SQL)-joins

Page 80 of 140
WK: 1 - Day: 1.1

One advantage of this approach is that we can have three specialized people or departments responsible for
maintaining their own data. We don't need a database administrator who is proficient with all aspects of our project to
shepherd one gigantic, multi-departmental database. Another advantage is that in the age of networks, each table
could reside on a different machine.
Now join PARTS and ORDERS:
SQL> SELECT O.ORDEREDON, O.NAME, O.PARTNUM, P.PARTNUM, P.DESCRIPTION
FROM ORDERS O, PART P;
ORDEREDON
----------15-MAY-1996
19-MAY-1996
2-SEP-1996
30-JUN-1996
30-JUN-1996
30-MAY-1996
30-MAY-1996
17-JAN-1996
17-JAN-1996
1-JUN-1996
1-JUN-1996
1-JUL-1996
1-JUL-1996
11-JUL-1996
...

NAME
PARTNUM
---------- ----------TRUE WHEEL
23
TRUE WHEEL
76
TRUE WHEEL
10
TRUE WHEEL
42
BIKE SPEC
54
BIKE SPEC
10
BIKE SPEC
23
BIKE SPEC
76
LE SHOPPE
76
LE SHOPPE
10
AAA BIKE
10
AAA BIKE
76
AAA BIKE
46
JACKS BIKE
76

PARTNUM
--------54
54
54
54
54
54
54
54
54
54
54
54
54
54

DESCRIPTION
-----------PEDALS
PEDALS
PEDALS
PEDALS
PEDALS
PEDALS
PEDALS
PEDALS
PEDALS
PEDALS
PEDALS
PEDALS
PEDALS
PEDALS

Analysis:
The preceding code is just a portion of the result set. The actual set is 14 (number of rows in ORDERS) x 6 (number
of rows in PART), or 84 rows. It is similar to the result from joining EMP and DEPT on the top, and it is still one
statement shy of being useful. Before we reveal that statement, we need to regress a little and talk about another use
for the alias.

2. Finding the Correct Column


When we joined EMP and DEPT, we used SELECT *, which returned all the columns in both tables. In joining
ORDERS to PART, the SELECT statement is a bit more complicated:
SQL> SELECT O.ORDEREDON, O.NAME, O.PARTNUM, P.PARTNUM, P.DESCRIPTION
SQL is smart enough to know that ORDEREDON and NAME exist only in ORDERS and that DESCRIPTION exists
only in PART, but what about PARTNUM, which exists in both? If we have a column that has the same name in two
tables, we must use an alias in our SELECT clause to specify which column we want to display. A common technique
is to assign a single character to each table, as we did in the FROM clause:
FROM ORDERS O, PART P
We use that character with each column name, as we did in the preceding SELECT clause. The SELECT clause
could also be written like this:
SQL> SELECT ORDEREDON, NAME, O.PARTNUM, P.PARTNUM, DESCRIPTION
But remember, someday we might have to come back and maintain this query. It doesn't hurt to make it more
readable. Now back to the missing statement.

3. Equi-Joins
An extract from the PART/ORDERS join provides a clue as to what is missing:
30-JUN-1996 TRUE WHEEL
30-JUN-1996 BIKE SPEC
30-MAY-1996 BIKE SPEC

42
54
10

54 PEDALS
54 PEDALS
54 PEDALS

Notice the PARTNUM fields that are common to both tables. What if we wrote the following?
SQL> SELECT O.ORDEREDON, O.NAME, O.PARTNUM, P.PARTNUM, P.DESCRIPTION

Structure Query Language (SQL)-joins

Page 81 of 140
WK: 1 - Day: 1.1

FROM ORDERS O, PART P


WHERE O.PARTNUM = P.PARTNUM;
ORDEREDON
----------1-JUN-1996
30-MAY-1996
2-SEP-1996
1-JUN-1996
30-MAY-1996
15-MAY-1996
30-JUN-1996
1-JUL-1996
30-JUN-1996
1-JUL-1996
17-JAN-1996
19-MAY-1996
11-JUL-1996
17-JAN-1996

NAME
PARTNUM
---------- ----------AAA BIKE
10
BIKE SPEC
10
TRUE WHEEL
10
LE SHOPPE
10
BIKE SPEC
23
TRUE WHEEL
23
TRUE WHEEL
42
AAA BIKE
46
BIKE SPEC
54
AAA BIKE
76
BIKE SPEC
76
TRUE WHEEL
76
JACKS BIKE
76
LE SHOPPE
76

PARTNUM
--------10
10
10
10
23
23
42
46
54
76
76
76
76
76

DESCRIPTION
-------------TANDEM
TANDEM
TANDEM
TANDEM
MOUNTAIN BIKE
MOUNTAIN BIKE
SEATS
TIRES
PEDALS
ROAD BIKE
ROAD BIKE
ROAD BIKE
ROAD BIKE
ROAD BIKE

Analysis:
Using the column PARTNUM that exists in both of the preceding tables, we have just combined the information we
had stored in the ORDERS table with information from the PART table to show a description of parts the bike shops
have ordered from us. The join that was used is called an EQUI-JOIN because the goal is to match the values of a
column in one table to the corresponding values in the second table.
We can further qualify this query by adding more conditions in the WHERE clause. For example:
SQL> SELECT O.ORDEREDON, O.NAME, O.PARTNUM, P.PARTNUM, P.DESCRIPTION
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM AND O.PARTNUM = 76;
ORDEREDON
----------1-JUL-1996
17-JAN-1996
19-MAY-1996
11-JUL-1996
17-JAN-1996

NAME
PARTNUM
---------- ----------AAA BIKE
76
BIKE SPEC
76
TRUE WHEEL
76
JACKS BIKE
76
LE SHOPPE
76

PARTNUM
---------76
76
76
76
76

DESCRIPTION
-----------ROAD BIKE
ROAD BIKE
ROAD BIKE
ROAD BIKE
ROAD BIKE

The number 76 is not very descriptive, and we wouldn't want our sales people to have to memorize a part number.
(We have had the misfortune to see many data information systems in the field that require the end user to know
some obscure code for something that had a perfectly good name). Here's another way to write the query:
SQL> SELECT O.ORDEREDON, O.NAME, O.PARTNUM, P.PARTNUM, P.DESCRIPTION
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM AND P.DESCRIPTION = 'ROAD BIKE';
ORDEREDON
----------1-JUL-1996
17-JAN-1996
19-MAY-1996
11-JUL-1996
17-JAN-1996

NAME
PARTNUM
---------- ----------AAA BIKE
76
BIKE SPEC
76
TRUE WHEEL
76
JACKS BIKE
76
LE SHOPPE
76

PARTNUM
---------76
76
76
76
76

DESCRIPTION
-----------ROAD BIKE
ROAD BIKE
ROAD BIKE
ROAD BIKE
ROAD BIKE

Find out how much money we have made from selling road bikes:
SQL> SELECT SUM(O.QUANTITY * P.PRICE) TOTAL
FROM ORDERS O, PART P
WHERE O.PARTNUM - P.PARTNUM AND P.DESCRIPTION - 'ROAD BIKE';
TOTAL
----------19610.00

Structure Query Language (SQL)-joins

Page 82 of 140
WK: 1 - Day: 1.1

Analysis:
With this setup, the sales people can keep the ORDERS table updated, the production department can keep the
PART table current, and we can find our bottom line without redesigning our database.
Note: Notice the consistent use of table and column aliases in the SQL statement examples. We will save many,
many keystrokes by using aliases. They also help to make our statement more readable.
Can we join more than one table? For ex, to generate information to send out an invoice, we could type this
statement:
SQL> SELECT C.NAME, C.ADDRESS, (O.QUANTITY * P.PRICE) TOTAL
FROM ORDER O, PART P, CUSTOMER C
WHERE O.PARTNUM = P.PARTNUM
AND O.NAME = C.NAME;
When 3 tables are used equivalence on all three has to be specified.
NAME
---------TRUE WHEEL
BIKE SPEC
LE SHOPPE
AAA BIKE
TRUE WHEEL
BIKE SPEC
TRUE WHEEL
AAA BIKE
BIKE SPEC
TRUE WHEEL
BIKE SPEC
JACKS BIKE
LE SHOPPE
AAA BIKE

ADDRESS
TOTAL
---------- ----------55O HUSKER
1200.00
CPT SHRIVE
2400.00
HOMETOWN
3600.00
10 OLDTOWN
1200.00
55O HUSKER
2102.70
CPT SHRIVE
2803.60
55O HUSKER
196.00
10 OLDTOWN
213.50
CPT SHRIVE
542.50
55O HUSKER
1590.00
CPT SHRIVE
5830.00
24 EGLIN
7420.00
HOMETOWN
2650.00
10 OLDTOWN
2120.00

We could make the output more readable by writing the statement like this:
SQL> SELECT C.NAME, C.ADDRESS, O.QUANTITY * P.PRICE TOTAL
FROM ORDERS O, PART P, CUSTOMER C
WHERE O.PARTNUM = P.PARTNUM AND O.NAME = C.NAME ORDER BY C.NAME;
NAME
---------AAA BIKE
AAA BIKE
AAA BIKE
BIKE SPEC
BIKE SPEC
BIKE SPEC
BIKE SPEC
JACKS BIKE
LE SHOPPE
LE SHOPPE
TRUE WHEEL
TRUE WHEEL
TRUE WHEEL
TRUE WHEEL

ADDRESS
TOTAL
---------- ----------10 OLDTOWN
213.50
10 OLDTOWN
2120.00
10 OLDTOWN
1200.00
CPT SHRIVE
542.50
CPT SHRIVE
2803.60
CPT SHRIVE
5830.00
CPT SHRIVE
2400.00
24 EGLIN
7420.00
HOMETOWN
2650.00
HOMETOWN
3600.00
55O HUSKER
196.00
55O HUSKER
2102.70
55O HUSKER
1590.00
55O HUSKER
1200.00

Note: Notice that when joining the three tables (ORDERS, PART, and CUSTOMER) that the ORDERS table was
used in two joins and the other tables were used only once. Tables that will return the fewest rows with the given
conditions are commonly referred to as driving tables, or base tables. Tables other than the base table in a query are
usually joined to the base table for more efficient data retrieval. Consequently, the ORDERS table is the base table in
this example. In most databases a few base tables join (either directly or indirectly) all the other tables.
We can make the previous query more specific, thus more useful, by adding the DESCRIPTION column as in the
following example:
SQL> SELECT C.NAME, C.ADDRESS, O.QUANTITY * P.PRICE TOTAL, P.DESCRIPTION
FROM ORDERS O, PART P, CUSTOMER C

Structure Query Language (SQL)-joins

Page 83 of 140
WK: 1 - Day: 1.1

WHERE O.PARTNUM - P.PARTNUM AND O.NAME - C.NAME ORDER BY C.NAME;


NAME
---------AAA BIKE
AAA BIKE
AAA BIKE
BIKE SPEC
BIKE SPEC
BIKE SPEC
BIKE SPEC
JACKS BIKE
LE SHOPPE
LE SHOPPE
TRUE WHEEL
TRUE WHEEL
TRUE WHEEL
TRUE WHEEL

ADDRESS
TOTAL DESCRIPTION
---------- ----------- -------------10 OLDTOWN
213.50 TIRES
10 OLDTOWN
2120.00 ROAD BIKE
10 OLDTOWN
1200.00 TANDEM
CPT SHRIVE
542.50 PEDALS
CPT SHRIVE
2803.60 MOUNTAIN BIKE
CPT SHRIVE
5830.00 ROAD BIKE
CPT SHRIVE
2400.00 TANDEM
24 EGLIN
7420.00 ROAD BIKE
HOMETOWN
2650.00 ROAD BIKE
HOMETOWN
3600.00 TANDEM
55O HUSKER
196.00 SEATS
55O HUSKER
2102.70 MOUNTAIN BIKE
55O HUSKER
1590.00 ROAD BIKE
55O HUSKER
1200.00 TANDEM

Analysis:
This information is a result of joining three tables. We can now use this information to create an invoice.
Note: In the example, SQL grouped EMP and DEPT to create a new table with X (rows in EMP) x Y (rows in DEPT)
number of rows. A physical table is not created by the join, but rather in a virtual sense. The join between the two
tables produces a new set that meets all conditions in the WHERE clause, including the join itself. The SELECT
statement has reduced the number of rows displayed, but to evaluate the WHERE clause SQL still creates all the
possible rows. The sample tables in today's examples have only a handful of rows. Our actual data may have
thousands of rows. If we are working on a platform with lots of horsepower, using a multiple-table join might not
visibly affect performance. However, if we are working in a slower environment, joins could cause a significant
slowdown.
We aren't telling us not to use joins, because we have seen the advantages to be gained from a relational design.
Just be aware of the platform we are using and our customer's requirements for speed versus reliability.

4. Non-Equi Joins
Because SQL supports an equi-join, we might assume that SQL also has a non-equi-join. Whereas the equi-join uses
an (=) sign in the WHERE statement, the non-equi-join uses everything but an > or < sign. For example:
SQL> SELECT O.NAME, O.PARTNUM, P.PARTNUM, O.QUANTITY * P.PRICE TOTAL
FROM ORDERS O, PART P
WHERE O.PARTNUM > P.PARTNUM;
NAME
PARTNUM
PARTNUM
TOTAL
---------- ----------- ----------- ----------TRUE WHEEL
76
54
162.75
BIKE SPEC
76
54
596.75
LE SHOPPE
76
54
271.25
AAA BIKE
76
54
217.00
JACKS BIKE
76
54
759.50
TRUE WHEEL
76
42
73.50
BIKE SPEC
54
42
245.00
BIKE SPEC
76
42
269.50
LE SHOPPE
76
42
122.50
AAA BIKE
76
42
98.00
AAA BIKE
46
42
343.00
JACKS BIKE
76
42
343.00
TRUE WHEEL
76
46
45.75
BIKE SPEC
54
46
152.50
BIKE SPEC
76
46
167.75
LE SHOPPE
76
46
76.25
AAA BIKE
76
46
61.00
JACKS BIKE
76
46
213.50
TRUE WHEEL
76
23
1051.35
TRUE WHEEL
42
23
2803.60

Structure Query Language (SQL)-joins

Page 84 of 140
WK: 1 - Day: 1.1

...

Analysis:
This listing goes on to describe all the rows in the join WHERE O.PARTNUM > P.PARTNUM. In the context of our
bicycle shop, this information doesn't have much meaning, and in the real world the equi-join is far more common
than the non-equi-join. However, we may encounter an application in which a non-equi-join produces the perfect
result.

5. Outer Joins versus Inner Joins


Just as the non-equi-join balances the equi-join, an outer join complements the inner join. An inner join is where the
rows of the tables are combined with each other, producing a number of new rows equal to the product of the number
of rows in each table. Also, the inner join uses these rows to determine the result of the WHERE clause. An outer join
groups the two tables in a slightly different way. Using the PART and ORDERS tables from the previous examples,
perform the following inner join:
SQL> SELECT P.PARTNUM, P.DESCRIPTION, P.PRICE, O.NAME, O.PARTNUM
FROM PART P
JOIN ORDERS O ON O.PARTNUM = 54;
PARTNUM
------54
42
46
23
76
10

DESCRIPTION
PRICE NAME
PARTNUM
-------------------- ----------- ---------- ----------PEDALS
54.25 BIKE SPEC
54
SEATS
24.50 BIKE SPEC
54
TIRES
15.25 BIKE SPEC
54
MOUNTAIN BIKE
350.45 BIKE SPEC
54
ROAD BIKE
530.00 BIKE SPEC
54
TANDEM
1200.00 BIKE SPEC
54

Note: The syntax we used to get this join JOIN ON is not ANSI standard. The implementation we used for this
example has additional syntax. We are using it here to specify an inner and an outer join. Most implementations of
SQL have similar extensions. Notice the absence of the WHERE clause in this type of join.

Analysis:
The result is that all the rows in PART are spliced on to specific rows in ORDERS where the column PARTNUM is
54. Here's a RIGHT OUTER JOIN statement:
SQL> SELECT P.PARTNUM, P.DESCRIPTION, P.PRICE, O.NAME, O.PARTNUM
FROM PART P
RIGHT OUTER JOIN ORDERS O ON O.PARTNUM = 54;
PARTNUM
------<null>
<null>
<null>
<null>
54
42
46
23
76
10
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>

DESCRIPTION
PRICE
-------------------- ------<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
PEDALS
54.25
SEATS
24.50
TIRES
15.25
MOUNTAIN BIKE
350.45
ROAD BIKE
530.00
TANDEM
1200.00
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>
<null>

NAME
PARTNUM
-------------- ------TRUE WHEEL
23
TRUE WHEEL
76
TRUE WHEEL
10
TRUE WHEEL
42
BIKE SPEC
54
BIKE SPEC
54
BIKE SPEC
54
BIKE SPEC
54
BIKE SPEC
54
BIKE SPEC
54
BIKE SPEC
10
BIKE SPEC
23
BIKE SPEC
76
LE SHOPPE
76
LE SHOPPE
10
AAA BIKE
10
AAA BIKE
76
AAA BIKE
46
JACKS BIKE
76

Structure Query Language (SQL)-joins

Page 85 of 140
WK: 1 - Day: 1.1

Analysis:
This query is new. First we specified a RIGHT OUTER JOIN, which caused SQL to return a full set of right table,
ORDERS, and to place nulls in fields where ORDERS.PARTNUM = 54. Following is a LEFT OUTER JOIN statement:
SQL> SELECT P.PARTNUM, P.DESCRIPTION, P.PRICE, O.NAME, O.PARTNUM
FROM PART P
LEFT OUTER JOIN ORDERS O ON ORDERS.PARTNUM = 54;
PARTNUM
------54
42
46
23
76
10

DESCRIPTION
PRICE NAME
PARTNUM
------------------ ----------- ---------- ----------PEDALS
54.25 BIKE SPEC
54
SEATS
24.50 BIKE SPEC
54
TIRES
15.25 BIKE SPEC
54
MOUNTAIN BIKE
350.45 BIKE SPEC
54
ROAD BIKE
530.00 BIKE SPEC
54
TANDEM
1200.00 BIKE SPEC
54

Analysis:
We get the same six rows as the INNER JOIN. Because we specified LEFT (the LEFT table), PART determined the
number of rows we would return. Because PART is smaller than ORDERS, SQL saw no need to pad those other
fields with blanks. Some implementations of SQL use the + sign instead of an OUTER JOIN statement. The + simply
means "Show me everything even if something is missing." Here's the syntax:

Syntax:
SQL> SELECT P.PARTNUM, P.DESCRIPTION, P.PRICE, O.NAME, O.PARTNUM
FROM PART P, ORDERS O
WHERE P.PARTNUM = O.PARTNUM(+) AND O.NAME LIKE '%BIKE%';

Analysis:
This statement is joining two tables. The + sign on the O.PARTNUM column will return all rows even if they are
empty.

6. Joining a Table to Itself


The often-used technique of joining a table to itself. The syntax of this operation is similar to joining two tables. For
example, to join table EMP to itself, type this:
SQL> SELECT *
FROM EMP, DEPT;
EMPNO
----7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934
7369
7499
7521
7566
7654
7698

ENAME
----SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE

JOB
--------CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK
CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER

MGR
---7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782
7902
7698
7698
7839
7698
7839

HIREDATE
--------17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82
17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81

SAL
---800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300
800
1600
1250
2975
1250
2850

COMM DEPTNO DEPTNO


---- ------ -----20
10
300
30
10
500
30
10
20
10
1400
30
10
30
10
10
10
20
10
10
10
0
30
10
20
10
30
10
20
10
10
10
20
20
300
30
20
500
30
20
20
20
1400
30
20
30
20

DNAME
---------ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
ACCOUNTING
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH

LOC
-------NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
NEW YORK
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS

Structure Query Language (SQL)-joins

7782
7788
7839
7844
7876
7900
7902
7934
7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934
7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934

CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER

MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK
CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK
CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK

7839
7566
7698
7788
7698
7566
7782
7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782
7902
7698
7698
7839
7698
7839
7839
7566
7698
7788
7698
7566
7782

Page 86 of 140
WK: 1 - Day: 1.1

09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82
17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82
17-DEC-80
20-FEB-81
22-FEB-81
02-APR-81
28-SEP-81
01-MAY-81
09-JUN-81
19-APR-87
17-NOV-81
08-SEP-81
23-MAY-87
03-DEC-81
03-DEC-81
23-JAN-82

2450
3000
5000
1500
1100
950
3000
1300
800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300
800
1600
1250
2975
1250
2850
2450
3000
5000
1500
1100
950
3000
1300

300
500
1400

300
500
1400

10
20
10
30
20
30
20
10
20
30
30
20
30
30
10
20
10
30
20
30
20
10
20
30
30
20
30
30
10
20
10
30
20
30
20
10

20
20
20
20
20
20
20
20
30
30
30
30
30
30
30
30
30
30
30
30
30
30
40
40
40
40
40
40
40
40
40
40
40
40
40
40

RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
RESEARCH
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
SALES
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS
OPERATIONS

DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
DALLAS
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
CHICAGO
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON
BOSTON

56 rows selected.

Analysis:
In its complete form, this join produces the same number of combinations as joining two 6-row tables. This type of
join could be useful to check the internal consistency of data. What would happen if someone fell asleep in the
production department and entered a new part with a PARTNUM that already existed? That would be bad news for
everybody: Invoices would be wrong; our application would probably blow up; and in general we would be in for a
very bad time. And the cause of all our problems would be the duplicate PARTNUM in the following table:
We saved our company from this bad situation by checking PART before anyone used it:
SQL> SELECT F.PARTNUM, F.DESCRIPTION, S.PARTNUM, S.DESCRIPTION
FROM PART F, PART S
WHERE F.PARTNUM = S.PARTNUM AND F.DESCRIPTION <> S.DESCRIPTION;
PARTNUM
---------76
76

DESCRIPTION
PARTNUM DESCRIPTION
------------------------ ------- -----------ROAD BIKE
76 CLIPPLESS SHOE
CLIPPLESS SHOE
76 ROAD BIKE

Analysis:
The join produced two rows that satisfied the condition WHERE F.PARTNUM = S.PARTNUM AND F.DESCRIPTION
<> S.DESCRIPTION. Of course, at some point, the row of data containing the duplicate PARTNUM would have to be
corrected.

Structure Query Language (SQL)-Sub Queries

Page 87 of 140
WK: 1 - Day: 1.1

Sub Queries
A subquery is a query whose results are passed as the argument for another query. Sub queries enable us to bind
several queries together. We will understand and be able to do the following:





Build a subquery
Use the keywords EXISTS, ANY, and ALL with our sub queries
Build and use correlated sub queries

1. Building a Subquery
Simply put, a subquery let us tie the result set of one query to another. The general syntax is as follows:

Syntax:
SQL> SELECT *
FROM TABLE1
WHERE TABLE1.SOMECOLUMN =
(SELECT SOMEOTHERCOLUMN
FROM TABLE2
WHERE SOMEOTHERCOLUMN - SOMEVALUE)
Notice how the second query is nested inside the first. Here's a real example that uses the PART and ORDERS
tables:
SQL> SELECT *
FROM PART;
PARTNUM
----------54
42
46
23
76
10

DESCRIPTION
PRICE
-------------------- ----------PEDALS
54.25
SEATS
24.50
TIRES
15.25
MOUNTAIN BIKE
350.45
ROAD BIKE
530.00
TANDEM
1200.00

SQL> SELECT *
FROM ORDERS;
ORDEREDON
----------15-MAY-1996
19-MAY-1996
2-SEP-1996
30-JUN-1996
30-JUN-1996
30-MAY-1996
30-MAY-1996
17-JAN-1996
17-JAN-1996
1-JUN-1996
1-JUN-1996
1-JUL-1996
1-JUL-1996
11-JUL-1996

NAME
PARTNUM
QUANTITY REMARKS
---------- ----------- ----------- -------TRUE WHEEL
23
6 PAID
TRUE WHEEL
76
3 PAID
TRUE WHEEL
10
1 PAID
TRUE WHEEL
42
8 PAID
BIKE SPEC
54
10 PAID
BIKE SPEC
10
2 PAID
BIKE SPEC
23
8 PAID
BIKE SPEC
76
11 PAID
LE SHOPPE
76
5 PAID
LE SHOPPE
10
3 PAID
AAA BIKE
10
1 PAID
AAA BIKE
76
4 PAID
AAA BIKE
46
14 PAID
JACKS BIKE
76
14 PAID

Analysis:
The tables share a common field called PARTNUM. Suppose we don't know the PARTNUM, but instead wanted to
work with the description of the part. Using a subquery, we could type this:
SQL> SELECT *
FROM ORDERS
WHERE PARTNUM =

Structure Query Language (SQL)-Sub Queries

Page 88 of 140
WK: 1 - Day: 1.1

(SELECT PARTNUM
FROM PART
WHERE DESCRIPTION LIKE ROAD%);
ORDEREDON
----------19-MAY-1996
17-JAN-1996
17-JAN-1996
1-JUL-1996
11-JUL-1996

NAME
PARTNUM
QUANTITY REMARKS
---------- ----------- ----------- -------TRUE WHEEL
76
3 PAID
BIKE SPEC
76
11 PAID
LE SHOPPE
76
5 PAID
AAA BIKE
76
4 PAID
JACKS BIKE
76
14 PAID

Analysis:
We can enhance the PARTNUM column in the result by including the DESCRIPTION, making PARTNUM clearer for
anyone who hasn't memorized it. Try this:
SQL> SELECT O.ORDEREDON, O.PARTNUM, P.DESCRIPTION, O.QUANTITY, O.REMARKS
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM
AND O.PARTNUM = (SELECT PARTNUM
FROM PART
WHERE DESCRIPTION LIKE ROAD%);
ORDEREDON
PARTNUM DESCRIPTION
QUANTITY REMARKS
----------- ----------- ------------ ----------- --------19-MAY-1996
76 ROAD BIKE
3 PAID
1-JUL-1996
76 ROAD BIKE
4 PAID
17-JAN-1996
76 ROAD BIKE
5 PAID
17-JAN-1996
76 ROAD BIKE
11 PAID
11-JUL-1996
76 ROAD BIKE
14 PAID

Analysis:
The first part of the query is very familiar:
SQL> SELECT O.ORDEREDON, O.PARTNUM, P.DESCRIPTION, O.QUANTITY, O.REMARKS
FROM ORDERS O, PART P
Here we are using the aliases O and P for tables ORDERS and PART to select the five columns we are interested in.
In this case the aliases were not necessary because each of the columns we asked to return is unique. However, it is
easier to make a readable query now than to have to figure it out later. The first WHERE clause we encounter
WHERE O.PARTNUM = P.PARTNUM
Is standard language for the join of tables PART and ORDERS specified in the FROM clause. If we didn't use this
WHERE clause, we would have all the possible row combinations of the two tables. The next section includes the
subquery. The statement
AND
O.PARTNUM =
(SELECT PARTNUM
FROM PART
WHERE DESCRIPTION LIKE ROAD%)
Adds the qualification that O.PARTNUM must be equal to the result of our simple subquery. The subquery is
straightforward, finding all the part numbers that are LIKE "ROAD%". The use of LIKE was somewhat lazy, saving we
the keystrokes required to type ROAD BIKE. However, it turns out we were lucky this time. What if someone in the
Parts department had added a new part called ROADKILL? The revised PART table would look like this:
SQL> SELECT *
FROM PART;
PARTNUM
----------54
42
46

DESCRIPTION
PRICE
-------------------- ----------PEDALS
54.25
SEATS
24.50
TIRES
15.25

Structure Query Language (SQL)-Sub Queries

23
76
10
77

MOUNTAIN BIKE
ROAD BIKE
TANDEM
ROADKILL

Page 89 of 140
WK: 1 - Day: 1.1

350.45
530.00
1200.00
7.99

Suppose we are blissfully unaware of this change and try our query after this new product was added. If we enter
this:
SQL> SELECT O.ORDEREDON, O.PARTNUM, P.DESCRIPTION, O.QUANTITY, O.REMARKS
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM
AND O.PARTNUM = (SELECT PARTNUM
FROM PART
WHERE DESCRIPTION LIKE ROAD%);
The SQL engine complains multiple rows in singleton select and we don't get any results. The response from our
SQL engine may vary, but it still complains and returns nothing.
To find out why we get this undesirable result, assume the role of the SQL engine. We will probably evaluate the
subquery first. We would return this:
SQL> SELECT PARTNUM
FROM PART
WHERE DESCRIPTION LIKE ROAD%;
PARTNUM
----------76
77
The = can only be on one. Say a=b not a=b,c. so it is wrong. But like works.
We would take this result and apply it to O.PARTNUM =, which is the step that causes the problem.

Analysis:
How can PARTNUM be equal to both 76 and 77? This must be what the engine meant when it accused we of being a
simpleton. When we used the LIKE clause, we opened yourself up for this error. When we combine the results of a
relational operator with another relational operator, such as =, <, or >, we need to make sure the result is singular. In
the case of the example we have been using, the solution would be to rewrite the query using an = instead of the
LIKE, like this:
SQL> SELECT O.ORDEREDON, O.PARTNUM, P.DESCRIPTION, O.QUANTITY, O.REMARKS
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM
AND O.PARTNUM = (SELECT PARTNUM
FROM PART
WHERE DESCRIPTION = ROAD BIKE);
ORDEREDON
PARTNUM DESCRIPTION
QUANTITY REMARKS
----------- ----------- --------------- ----------- ---------19-MAY-1996
76 ROAD BIKE
3 PAID
1-JUL-1996
76 ROAD BIKE
4 PAID
17-JAN-1996
76 ROAD BIKE
5 PAID
17-JAN-1996
76 ROAD BIKE
11 PAID
11-JUL-1996
76 ROAD BIKE
14 PAID

Analysis:
This subquery returns only one unique result; therefore narrowing our = condition to a single value. How can we be
sure the subquery won't return multiple values if we are looking for only one value?
Avoiding the use of LIKE is a start. Another approach is to ensure the uniqueness of the search field during table
design. If we are the untrusting type, we could use the method for joining a table to itself to check a given field for
uniqueness. If we design the table yourself or trust the person who designed the table, we could require the column
we are searching to have a unique value. We could also use a part of SQL that returns only one answer: the
aggregate function.

Structure Query Language (SQL)-Sub Queries

Page 90 of 140
WK: 1 - Day: 1.1

2. Using Aggregate Functions with Subqueries


The aggregate functions SUM, COUNT, MIN, MAX, and AVG all return a single value. To find the average amount of
an order, type this:
SQL> SELECT AVG(O.QUANTITY * P.PRICE)
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM;
AVG
----------2419.16

Analysis:
This statement returns only one value. To find out which orders were above average, use the preceding SELECT
statement for our subquery. The complete query and result are as follows:
SQL> SELECT O.NAME, O.ORDEREDON, O.QUANTITY * P.PRICE TOTAL
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM
AND O.QUANTITY * P.PRICE > (SELECT AVG(O.QUANTITY * P.PRICE)
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM);
NAME
---------LE SHOPPE
BIKE SPEC
LE SHOPPE
BIKE SPEC
JACKS BIKE

ORDEREDON
TOTAL
----------- ----------1-JUN-1996
3600.00
30-MAY-1996
2803.60
17-JAN-1996
2650.00
17-JAN-1996
5830.00
11-JUL-1996
7420.00

Analysis:
This example contains a rather unremarkable SELECT/FROM/WHERE clause:
SQL> SELECT O.NAME, O.ORDEREDON, O.QUANTITY * P.PRICE TOTAL
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM;
These lines represent the common way of joining these two tables. This join is necessary because the price is in
PART and the quantity is in ORDERS. The WHERE ensures that we examine only the join-formed rows that are
related. We then add the subquery:
AND
O.QUANTITY * P.PRICE >
(SELECT AVG(O.QUANTITY * P.PRICE)
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM)
The preceding condition compares the total of each order with the average we computed in the subquery. Note that
the join in the subquery is required for the same reasons as in the main SELECT statement. This join is also
constructed exactly the same way. They have exactly the same syntax as a standalone query. In fact, most
subqueries start out as standalone queries and are incorporated as subqueries after their results are tested.

3. Nested Subqueries
Nesting is the act of embedding a subquery within another subquery. For example:
SQL> SELECT *
FROM SOMETHING
WHERE (SUBQUERY(SUBQUERY(SUBQUERY)));
Subqueries can be nested as deeply as our implementation of SQL allows. For example, to send out special notices
to customers who spend more than the average amount of money, we would combine the information in the table
CUSTOMER

Structure Query Language (SQL)-Sub Queries

Page 91 of 140
WK: 1 - Day: 1.1

SQL> SELECT *
FROM CUSTOMER;
NAME
---------TRUE WHEEL
BIKE SPEC
LE SHOPPE
AAA BIKE
JACKS BIKE

ADDRESS
---------55O HUSKER
CPT SHRIVE
HOMETOWN
10 OLDTOWN
24 EGLIN

STATE
-----NE
LA
KS
NE
FL

ZIP
---------58702
45678
54678
56784
34567

PHONE
----------555-4545
555-1234
555-1278
555-3421
555-2314

REMARKS
---------NONE
NONE
NONE
JOHN-MGR
NONE

With a slightly modified version of the query we used to find the above-average orders:
SQL> SELECT ALL C.NAME, C.ADDRESS, C.STATE, C.ZIP
FROM CUSTOMER C
WHERE C.NAME IN (SELECT O.NAME
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM AND
O.QUANTITY * P.PRICE > (SELECT AVG(O.QUANTITY * P.PRICE)
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM));
NAME
---------BIKE SPEC
LE SHOPPE
JACKS BIKE

ADDRESS
---------CPT SHRIVE
HOMETOWN
24 EGLIN

STATE
-----LA
KS
FL

ZIP
---------45678
54678
34567

Analysis:
Here's a look at what we asked for. In the inner most set of parentheses, we find a familiar statement:
SQL> SELECT AVG(O.QUANTITY * P.PRICE)
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM;
This result feeds into a slightly modified version of the SELECT clause we used before:
SQL> SELECT O.NAME
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM AND O.QUANTITY * P.PRICE
(...)

>

Note the SELECT clause has been modified to return a single column, NAME, which, not so coincidentally, is
common with the table CUSTOMER. Running this statement by itself we get:
SQL> SELECT O.NAME
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM AND O.QUANTITY * P.PRICE
(SELECT AVG(O.QUANTITY * P.PRICE)
FROM ORDERS O, PART P
WHERE O.PARTNUM = P.PARTNUM);

>

NAME
---------LE SHOPPE
BIKE SPEC
LE SHOPPE
BIKE SPEC
JACKS BIKE

Analysis:
We just spent some time discussing why our subqueries should return just one value. The reason this query was able
to return more than one value becomes apparent in a moment.
We bring these results to the statement:
SQL> SELECT C.NAME, C.ADDRESS, C.STATE, C.ZIP

Structure Query Language (SQL)-Sub Queries

Page 92 of 140
WK: 1 - Day: 1.1

FROM CUSTOMER C
WHERE C.NAME IN
(...)

Analysis:
The first two lines are unremarkable. The third reintroduces the keyword IN. IN is the tool that enables us to use the
multiple-row output of our subquery. IN, as we remember, looks for matches in the following set of values enclosed
by parentheses, which in this case produces the following values:
LE SHOPPE
BIKE SPEC
LE SHOPPE
BIKE SPEC
JACKS BIKE
This subquery provides the conditions that give us the mailing list:
NAME
---------BIKE SPEC
LE SHOPPE
JACKS BIKE

ADDRESS
---------CPT SHRIVE
HOMETOWN
24 EGLIN

STATE
-----LA
KS
FL

ZIP
-----45678
54678
34567

This use of IN is very common in subqueries. Because IN uses a set of values for its comparison, it does not cause
the SQL engine to feel conflicted and inadequate.
Subqueries can also be used with GROUP BY and HAVING clauses. Examine the following query:
SQL> SELECT NAME, AVG(QUANTITY)
FROM ORDERS
GROUP BY NAME HAVING AVG(QUANTITY) >
(SELECT AVG(QUANTITY) FROM ORDERS);
NAME
AVG
---------- ----------BIKE SPEC
8
JACKS BIKE
14

Analysis:
Let's examine this query in the order the SQL engine would. First, look at the subquery:
SQL> SELECT AVG(QUANTITY)
FROM ORDERS;
AVG
----------6
By itself, the query is as follows:
SQL> SELECT NAME, AVG(QUANTITY)
FROM ORDERS
GROUP BY NAME;
NAME
AVG
---------- ----------AAA BIKE
6
BIKE SPEC
8
JACKS BIKE
14
LE SHOPPE
4
TRUE WHEEL
5
When combined through the HAVING clause, the subquery produces two rows that have above-average QUANTITY.
HAVING AVG(QUANTITY) >
(SELECT AVG(QUANTITY)
FROM ORDERS)

Structure Query Language (SQL)-Sub Queries

Page 93 of 140
WK: 1 - Day: 1.1

NAME
AVG
---------- ----------BIKE SPEC
8
JACKS BIKE
14

4. Correlated Sub queries


The sub queries we have written so far are self-contained. None of them have used a reference from outside the
subquery. Correlated sub queries enable us to use an outside reference with some strange and wonderful results.
Look at the following query:
SQL> SELECT *
FROM ORDERS O
WHERE 'ROAD BIKE' = (SELECT DESCRIPTION
FROM PART P
WHERE P.PARTNUM = O.PARTNUM);
ORDEREDON
----------19-MAY-1996
17-JAN-1996
17-JAN-1996
1-JUL-1996
11-JUL-1996

NAME
PARTNUM
QUANTITY REMARKS
---------- ----------- ----------- ---------TRUE WHEEL
76
3 PAID
BIKE SPEC
76
11 PAID
LE SHOPPE
76
5 PAID
AAA BIKE
76
4 PAID
JACKS BIKE
76
14 PAID

This query actually resembles the following JOIN:


SQL> SELECT O.ORDEREDON, O.NAME, O.PARTNUM, O.QUANTITY, O.REMARKS
FROM ORDERS O, PART P
WHERE P.PARTNUM = O.PARTNUM AND P.DESCRIPTION = 'ROAD BIKE';
ORDEREDON
----------19-MAY-1996
1-JUL-1996
17-JAN-1996
17-JAN-1996
11-JUL-1996

NAME
PARTNUM
QUANTITY REMARKS
---------- ----------- ----------- ------TRUE WHEEL
76
3 PAID
AAA BIKE
76
4 PAID
LE SHOPPE
76
5 PAID
BIKE SPEC
76
11 PAID
JACKS BIKE
76
14 PAID

Analysis:
In fact, except for the order, the results are identical. The correlated subquery acts very much like a join. The
correlation is established by using an element from the query in the subquery. In this example the correlation was
established by the statement
WHERE P.PARTNUM = O.PARTNUM
In which we compare P.PARTNUM, from the table inside our subquery, to O.PARTNUM, from the table outside our
query. Because O.PARTNUM can have a different value for every row, the correlated subquery is executed for each
row in the query. In the next example each row in the table ORDERS
SQL> SELECT *
FROM ORDERS;
ORDEREDON
----------15-MAY-1996
19-MAY-1996
2-SEP-1996
30-JUN-1996
30-JUN-1996
30-MAY-1996
30-MAY-1996
17-JAN-1996
17-JAN-1996
1-JUN-1996

NAME
PARTNUM
QUANTITY REMARKS
---------- ----------- ----------- ------TRUE WHEEL
23
6 PAID
TRUE WHEEL
76
3 PAID
TRUE WHEEL
10
1 PAID
TRUE WHEEL
42
8 PAID
BIKE SPEC
54
10 PAID
BIKE SPEC
10
2 PAID
BIKE SPEC
23
8 PAID
BIKE SPEC
76
11 PAID
LE SHOPPE
76
5 PAID
LE SHOPPE
10
3 PAID

Structure Query Language (SQL)-Sub Queries

1-JUN-1996
1-JUL-1996
1-JUL-1996
11-JUL-1996

AAA BIKE
AAA BIKE
AAA BIKE
JACKS BIKE

Page 94 of 140
WK: 1 - Day: 1.1

10
76
46
76

1
4
14
14

PAID
PAID
PAID
PAID

Is processed against the subquery criteria:


SQL> SELECT DESCRIPTION
FROM PART P
WHERE P.PARTNUM = O.PARTNUM;

Analysis:
This operation returns the DESCRIPTION of every row in PART where P.PARTNUM = O.PARTNUM. These
descriptions are then compared in the WHERE clause:
WHERE 'ROAD BIKE' =
Because each row is examined, the subquery in a correlated subquery can have more than one value. However,
don't try to return multiple columns or columns that don't make sense in the context of the WHERE clause. The
values returned still must match up against the operation specified in the WHERE clause. For example, in the query
we just did, returning the PRICE to compare with ROAD BIKE would have the following result:
SQL> SELECT *
FROM ORDERS O
WHERE 'ROAD BIKE' = (SELECT PRICE
FROM PART P
WHERE P.PARTNUM = O.PARTNUM);
Conversion error from string ROAD BIKE. Here's another example of something not to do:
SQL> SELECT *
FROM ORDERS O
WHERE 'ROAD BIKE' = (SELECT *
FROM PART P
WHERE P.PARTNUM = O.PARTNUM);

Analysis:
The SQL engine simply can't correlate all the columns in PART with the operator =. Correlated subqueries can also
be used with the GROUP BY and HAVING clauses. The following query uses a correlated subquery to find the
average total order for a particular part and then applies that average value to filter the total order grouped by
PARTNUM:
SQL> SELECT O.PARTNUM, SUM(O.QUANTITY*P.PRICE), COUNT(PARTNUM)
FROM ORDERS O, PART P
WHERE P.PARTNUM = O.PARTNUM
GROUP BY O.PARTNUM HAVING SUM(O.QUANTITY*P.PRICE) >
(SELECT AVG(O1.QUANTITY * P1.PRICE)
FROM PART P1, ORDERS O1
WHERE P1.PARTNUM = O1.PARTNUM AND P1.PARTNUM = O.PARTNUM);
PARTNUM
SUM
COUNT
----------- ----------- ----------10
8400.00
4
23
4906.30
2
76
19610.00
5

Analysis:
The subquery does not just compute one
AVG(O1.QUANTITY*P1.PRICE)
Because of the correlation between the query and the subquery,
AND P1.PARTNUM - O.PARTNUM
This average is computed for every group of parts and then compared:

Structure Query Language (SQL)-Sub Queries

Page 95 of 140
WK: 1 - Day: 1.1

HAVING SUM(O.QUANTITY*P.PRICE) >


Tip: When using correlated subqueries with GROUP BY and HAVING, the columns in the HAVING clause must exist
in either the SELECT clause or the GROUP BY clause. Otherwise, we get an error message along the lines of invalid
column reference because the subquery is evoked for each group, not each row. We cannot make a valid
comparison to something that is not used in forming the group.

5. EXISTS, ANY, and ALL


The usage of the keywords EXISTS, ANY, and ALL is not intuitively obvious to the casual observer. EXISTS takes a
subquery as an argument and returns TRUE if the subquery returns anything and FALSE if the result set is empty.
For example:
SQL> SELECT NAME, ORDEREDON
FROM ORDERS
WHERE EXISTS (SELECT * FROM ORDERS WHERE NAME = 'TRUE WHEEL');
NAME
---------TRUE WHEEL
TRUE WHEEL
TRUE WHEEL
TRUE WHEEL
BIKE SPEC
BIKE SPEC
BIKE SPEC
BIKE SPEC
LE SHOPPE
LE SHOPPE
AAA BIKE
AAA BIKE
AAA BIKE
JACKS BIKE

ORDEREDON
----------15-MAY-1996
19-MAY-1996
2-SEP-1996
30-JUN-1996
30-JUN-1996
30-MAY-1996
30-MAY-1996
17-JAN-1996
17-JAN-1996
1-JUN-1996
1-JUN-1996
1-JUL-1996
1-JUL-1996
11-JUL-1996

Analysis:
Not what we might expect. The subquery inside EXISTS is evaluated only once in this uncorrelated example.
Because the return from the subquery has at least one row, EXISTS evaluates to TRUE and all the rows in the query
are printed. If we change the subquery as shown next, we don't get back any results.
SQL> SELECT NAME, ORDEREDON
FROM ORDERS
WHERE EXISTS (SELECT * FROM ORDERS WHERE NAME = 'MOSTLY HARMLESS');

Analysis:
EXISTS evaluates to FALSE. The subquery does not generate a result set because MOSTLY HARMLESS is not one
of our names.
Note: Notice the use of SELECT * in the subquery inside the EXISTS. EXISTS does not care how many columns are
returned.
We could use EXISTS in this way to check on the existence of certain rows and control the output of our query based
on whether they exist. If we use EXISTS in a correlated subquery, it is evaluated for every case implied by the
correlation we set up. For example:
SQL> SELECT NAME, ORDEREDON
FROM ORDERS O
WHERE EXISTS
(SELECT * FROM CUSTOMER C
WHERE STATE = 'NE' AND C.NAME = O.NAME);
NAME
ORDEREDON
---------- ----------TRUE WHEEL 15-MAY-1996
TRUE WHEEL 19-MAY-1996
TRUE WHEEL 2-SEP-1996

Structure Query Language (SQL)-Sub Queries

Page 96 of 140
WK: 1 - Day: 1.1

TRUE WHEEL 30-JUN-1996


AAA BIKE
1-JUN-1996
AAA BIKE
1-JUL-1996
AAA BIKE
1-JUL-1996
This slight modification of our first uncorrelated query returns all the bike shops from Nebraska that made orders. The
following subquery is run for every row in the query correlated on the CUSTOMER name and ORDERS name:
SQL> (SELECT *
FROM CUSTOMER C
WHERE STATE = 'NE' AND C.NAME = O.NAME);

Analysis:
EXISTS is TRUE for those rows that have corresponding names in CUSTOMER located in NE. Otherwise, it returns
FALSE.
Closely related to EXISTS are the keywords ANY, ALL, and SOME. ANY and SOME are identical in function. An
optimist would say this feature provides the user with a choice. A pessimist would see this condition as one more
complication. Look at this query:
SQL> SELECT NAME, ORDEREDON
FROM ORDERS
WHERE NAME = ANY
(SELECT NAME
FROM ORDERS
WHERE NAME = 'TRUE WHEEL');
NAME
---------TRUE WHEEL
TRUE WHEEL
TRUE WHEEL
TRUE WHEEL

ORDEREDON
----------15-MAY-1996
19-MAY-1996
2-SEP-1996
30-JUN-1996

Analysis:
ANY compared the output of the following subquery to each row in the query, returning TRUE for each row of the
query that has a result from the subquery.
SQL> (SELECT NAME
FROM ORDERS
WHERE NAME = 'TRUE WHEEL');
Replacing ANY with SOME produces an identical result:
SQL> SELECT NAME, ORDEREDON
FROM ORDERS
WHERE NAME = SOME
(SELECT NAME
FROM ORDERS
WHERE NAME = 'TRUE WHEEL');
NAME
---------TRUE WHEEL
TRUE WHEEL
TRUE WHEEL
TRUE WHEEL

ORDEREDON
----------15-MAY-1996
19-MAY-1996
2-SEP-1996
30-JUN-1996

Analysis:
We may have already noticed the similarity to IN. The same query using IN is as follows:
SQL> SELECT NAME, ORDEREDON
FROM ORDERS
WHERE NAME IN
(SELECT NAME

Structure Query Language (SQL)-Sub Queries

Page 97 of 140
WK: 1 - Day: 1.1

FROM ORDERS
WHERE NAME = 'TRUE WHEEL');
NAME
---------TRUE WHEEL
TRUE WHEEL
TRUE WHEEL
TRUE WHEEL

ORDEREDON
----------15-MAY-1996
19-MAY-1996
2-SEP-1996
30-JUN-1996

Analysis:
As we can see, IN returns the same result as ANY and SOME. Has the world gone mad? Not yet. Can IN do this?
SQL> SELECT NAME, ORDEREDON
FROM ORDERS
WHERE NAME > ANY
(SELECT NAME
FROM ORDERS
WHERE NAME = 'JACKS BIKE');
NAME
---------TRUE WHEEL
TRUE WHEEL
TRUE WHEEL
TRUE WHEEL
LE SHOPPE
LE SHOPPE

ORDEREDON
----------15-MAY-1996
19-MAY-1996
2-SEP-1996
30-JUN-1996
17-JAN-1996
1-JUN-1996

The answer is no. IN works like multiple equals. ANY and SOME can be used with other relational operators such as
greater than or less than. ALL returns TRUE only if all the results of a subquery meet the condition. Oddly enough,
ALL is used most commonly as a double negative, as in this query:
SQL> SELECT NAME, ORDEREDON
FROM ORDERS
WHERE NAME <> ALL
(SELECT NAME
FROM ORDERS
WHERE NAME = 'JACKS BIKE');
NAME
---------TRUE WHEEL
TRUE WHEEL
TRUE WHEEL
TRUE WHEEL
BIKE SPEC
BIKE SPEC
BIKE SPEC
BIKE SPEC
LE SHOPPE
LE SHOPPE
AAA BIKE
AAA BIKE
AAA BIKE

ORDEREDON
----------15-MAY-1996
19-MAY-1996
2-SEP-1996
30-JUN-1996
30-JUN-1996
30-MAY-1996
30-MAY-1996
17-JAN-1996
17-JAN-1996
1-JUN-1996
1-JUN-1996
1-JUL-1996
1-JUL-1996

Analysis:
This statement returns everybody except JACKS BIKE. <>ALL evaluates to TRUE only if the result set does not
contain what is on the left of the <>.

Structure Query Language (SQL)-Data Types

Page 98 of 140
WK: 1 - Day: 1.1

Data Types
Each value manipulated by Oracle Database has a datatype. The datatype of a value associates a fixed set of
properties with the value. These properties cause Oracle to treat values of one datatype differently from values of
another. For example, we can add values of NUMBER datatype, but not values of RAW datatype.
When we create a table or cluster, we must specify a datatype for each of its columns. When we create a procedure
or stored function, we must specify a datatype for each of its arguments. These datatypes define the domain of
values that each column can contain or each argument can have. For example, DATE columns cannot accept the
value February 29 (except for a leap year) or the values 2 or 'SHOE'. Each value subsequently placed in a column
assumes the datatype of the column. For example, if we insert '01-JAN-98' into a DATE column, then Oracle treats
the '01-JAN-98' character string as a DATE value after verifying that it translates to a valid date.
Oracle Database provides a number of built-in datatypes as well as several categories for user-defined types that can
be used as datatypes. A datatype is either scalar or nonscalar. A scalar type contains an atomic value, whereas a
nonscalar (sometimes called a "collection") contains a set of values. A large object (LOB) is a special form of scalar
datatype representing a large scalar value of binary or character data. LOBs are subject to some restrictions that do
not affect other scalar types because of their size.
The Oracle precompilers recognize other datatypes in embedded SQL programs. These datatypes are called external
datatypes and are associated with host variables. Do not confuse built-in datatypes and user-defined types with
external datatypes.

1. Oracle Built-in Datatypes


The table that follows summarizes Oracle built-in datatypes. The syntax in the preceding sections is for the syntactic
elements. The codes listed for the datatypes are used internally by Oracle Database. The datatype code of a column
or object attribute is returned by the DUMP function.

Code

Datatype

Description

VARCHAR2(size
[BYTE | CHAR])

Variable-length character string having maximum length size bytes or characters.


Maximum size is 4000 bytes or characters, and minimum is 1 byte or 1 character.
We must specify size for VARCHAR2.
BYTE indicates that the column will have byte length semantics; CHAR indicates
that the column will have character semantics.

NVARCHAR2(size)

NUMBER[(precision Number having precision p and scale s. The precision p can range from 1 to 38.
[, scale]])
The scale s can range from -84 to 127.

LONG

Character data of variable length up to 2 gigabytes, or 231 -1 bytes. Provided for


backward compatibility.

12

DATE

Valid date range from January 1, 4712 BC to December 31, 9999 AD. The default
format is determined explicitly by the NLS_DATE_FORMAT parameter or implicitly
by the NLS_TERRITORY parameter. The size is fixed at 7 bytes. This datatype
contains the datetime fields YEAR, MONTH, DAY, HOUR, MINUTE, and
SECOND. It does not have fractional seconds or a time zone.

21

BINARY_FLOAT

32-bit floating point number. This datatype requires 5 bytes, including length byte.

22

BINARY_DOUBLE

64-bit floating point number. This datatype requires 9 bytes, including length byte.

180

TIMESTAMP
Year, month, and day values of date, as well as hour, minute, and second values
[(fractional_seco of time, where fractional_seconds_precision is the number of digits in the fractional
nds)]
part of the SECOND datetime field. Accepted values of
fractional_seconds_precision are 0 to 9. The default is 6. The default format is
determined explicitly by the NLS_DATE_FORMAT parameter or implicitly by the

Variable-length Unicode character string having maximum length size characters.


The number of bytes can be up to two times size for AL16UTF16 encoding and
three times size for UTF8 encoding. Maximum size is determined by the national
character set definition, with an upper limit of 4000 bytes. We must specify size for
NVARCHAR2.

Structure Query Language (SQL)-Data Types

Code

Datatype

Page 99 of 140
WK: 1 - Day: 1.1

Description
NLS_TERRITORY parameter. The sizes varies from 7 to 11 bytes, depending on
the precision. This datatype contains the datetime fields YEAR, MONTH, DAY,
HOUR, MINUTE, and SECOND. It contains fractional seconds but does not have a
time zone.

181

TIMESTAMP
[(fractional_seco
nds)] WITH TIME
ZONE

231

TIMESTAMP
All values of TIMESTAMP WITH TIME ZONE, with the following exceptions:
[(fractional_seco
 Data is normalized to database time zone when it is stored in the database.
nds)] WITH LOCAL
 When the data is retrieved, users see the data in the session time zone.
TIME ZONE
The default format is determined explicitly by the NLS_DATE_FORMAT parameter
or implicitly by the NLS_TERRITORY parameter. The sizes varies from 7 to 11
bytes, depending on the precision.

182

INTERVAL YEAR
Stores a period of time in years and months, where year_precision is the number
[(year_precision) of digits in the YEAR datetime field. Accepted values are 0 to 9. The default is 2.
] TO MONTH
The size is fixed at 5 bytes.

183

INTERVAL DAY
Stores a period of time in days, hours, minutes, and seconds, where
[(day_precision)]
 day_precision is the maximum number of digits in the DAY datetime field.
TO SECOND
Accepted values are 0 to 9. The default is 2.
[(fractional_seco
 fractional_seconds_precision is the number of digits in fractional part of the
nds)]
SECOND field. Accepted values are 0 to 9. The default is 6.
The size is fixed at 11 bytes.

23

RAW(size)

Raw binary data of length size bytes. Maximum size is 2000 bytes. We must
specify size for a RAW value.

24

LONG RAW

Raw binary data of variable length up to 2 gigabytes.

69

ROWID

Base 64 string representing the unique address of a row in its table. This datatype
is primarily for values returned by the ROWID pseudocolumn.

208

UROWID [(size)]

Base 64 string representing the logical address of a row of an index-organized


table. The optional size is the size of a column of type UROWID. The maximum
size and default is 4000 bytes.

96

CHAR [(size [BYTE Fixed-length character data of length size bytes. Maximum size is 2000 bytes or
| CHAR])]
characters. Default and minimum size is 1 byte.
BYTE and CHAR have the same semantics as for VARCHAR2.

96

NCHAR[(size)]

Fixed-length character data of length size characters. The number of bytes can be
up to two times size for AL16UTF16 encoding and three times size for UTF8
encoding. Maximum size is determined by the national character set definition,
with an upper limit of 2000 bytes. Default and minimum size is 1 character.

112

CLOB

A character large object containing single-byte or multibyte characters. Both fixedwidth and variable-width character sets are supported, both using the database
character set. Maximum size is (4 gigabytes - 1) * (database block size).

112

NCLOB

A character large object containing Unicode characters. Both fixed-width and


variable-width character sets are supported, both using the database national
character set. Maximum size is (4 gigabytes - 1) * (database block size). Stores
national character set data.

All values of TIMESTAMP as well as time zone displacement value, where


fractional_seconds_precision is the number of digits in the fractional part of the
SECOND datetime field. Accepted values are 0 to 9. The default is 6. The default
format is determined explicitly by the NLS_DATE_FORMAT parameter or implicitly
by the NLS_TERRITORY parameter. The size is fixed at 13 bytes. This datatype
contains the datetime fields YEAR, MONTH, DAY, HOUR, MINUTE, SECOND,
TIMEZONE_HOUR, and TIMEZONE_MINUTE. It has fractional seconds and an
explicit time zone.

Structure Query Language (SQL)-Data Types

Page 100 of 140


WK: 1 - Day: 1.1

Code

Datatype

Description

113

BLOB

A binary large object. Maximum size is (4 gigabytes - 1) * (database block size).

114

BFILE

Contains a locator to a large binary file stored outside the database. Enables byte
stream I/O access to external LOBs residing on the database server. Maximum
size is 4 gigabytes.

Datetime and Interval Datatypes


The datetime datatypes are DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, and TIMESTAMP WITH LOCAL
TIME ZONE. Values of datetime datatypes are sometimes called datetimes. The interval datatypes are INTERVAL
YEAR TO MONTH and INTERVAL DAY TO SECOND. Values of interval datatypes are sometimes called intervals.
Both datetimes and intervals are made up of fields. The values of these fields determine the value of the datatype.
This table lists the datetime fields and their possible values for datetimes and intervals.
To avoid unexpected results in our DML operations on datetime data, we can verify the database and session time
zones by querying the built-in SQL functions DBTIMEZONE and SESSIONTIMEZONE. If the time zones have not
been set manually, Oracle Database uses the operating system time zone by default. If the operating system time
zone is not a valid Oracle time zone, then Oracle uses UTC as the default value.

Datetime Field

Valid Values for Datetime

Valid Values for INTERVAL

YEAR

-4712 to 9999 (excluding year 0)

Any positive or negative integer

MONTH

01 to 12

0 to 11

DAY

01 to 31 (limited by the values of MONTH and YEAR,


according to the rules of the current NLS calendar
parameter)

Any positive or negative integer

HOUR

00 to 23

0 to 23

MINUTE

00 to 59

0 to 59

SECOND

00 to 59.9(n), where 9(n) is the precision of time fractional


seconds. The 9(n) portion is not applicable for DATE.

0 to 59.9(n), where 9(n) is the


precision of interval fractional
seconds

TIMEZONE_HOUR

-12 to 14 (This range accommodates daylight saving time


changes.) Not applicable for DATE or TIMESTAMP.

Not applicable

TIMEZONE_MINUTE 00 to 59. Not applicable for DATE or TIMESTAMP.

Not applicable

TIMEZONE_REGION Query the TZNAME column of the V$TIMEZONE_NAMES


data dictionary view. Not applicable for DATE or
TIMESTAMP.

Not applicable

TIMEZONE_ABBR

Query the TZABBREV column of the


Not applicable
V$TIMEZONE_NAMES data dictionary view. Not applicable
for DATE or TIMESTAMP.

Note: TIMEZONE_HOUR and TIMEZONE_MINUTE are specified together and interpreted as an entity in the format
+|- hh:mm, with values ranging from -12:59 to +14:00.

Structure Query Language (SQL)-TCL

Page 101 of 140


WK: 1 - Day: 1.1

Transactions Control
We have become an intermediate-level SQL and database user. If required, we could build a database with its
associated tables, each of which would contain several fields of different data types. Using proper design techniques,
we could leverage the information contained within this database into a powerful application.




The basics of transaction control


How to finalize and or cancel a transaction

1. Transaction Control
Transaction control, or transaction management, refers to the capability of a relational database management system
to perform database transactions. Transactions are units of work that must be done in a logical order and
successfully as a group or not at all. The term unit of work means that a transaction has a beginning and an end. If
anything goes wrong during the transaction, the entire unit of work can be canceled if desired. If everything looks
good, the entire unit of work can be saved to the database.
Banking Application
We are employed by First Federal Financial Bank to set up an application that handles checking account transactions
that consist of debits and credits to customers' checking accounts. We have set up a nice database, which has been
tested and verified to work correctly. After calling up our application, we verify that when we take $20 out of the
account, $20 actually disappears from the database. When we add $50.25 to the checking account, this deposit
shows up as expected. We proudly announce to our bosses that the system is ready to go, and several computers
are set up in a local branch to begin work.
Within minutes, we notice a situation that we did not anticipate: As one teller is depositing a check, another teller is
withdrawing money from the same account. Within minutes, many depositors' balances are incorrect because
multiple users are updating tables simultaneously. Unfortunately, these multiple updates are overwriting each other.
Shortly thereafter, our application is pulled offline for an overhaul. We will work through this problem with a database
called CHECKING. Within this database are two tables, shown in Tables 1 and Table 2.
Table 1. CUSTOMERS table.

Name

Address

City

Bill Turner

725 N. Deal Parkway

John Keith

1220 Via De Luna Dr.

State

Zip

Customer_ID

Washington DC

20085

Jacksonville FL

33581

Mary Rosenberg 482 Wannamaker Avenue Williamsburg VA

23478

David Blanken

405 N. Davis Highway

Greenville

SC

29652

Rebecca Little

7753 Woods Lane

Houston

TX

38764

Table 2. BALANCES table.

Average_Bal

Curr_Bal

Account_ID

1298.53

854.22

5427.22

6015.96

211.25

190.01

73.79

25.87

1285.90

1473.75

1234.56

1543.67

345.25

348.03

Assume now that our application program performs a SELECT operation and retrieves the following data for Bill
Turner:

Structure Query Language (SQL)-TCL

Page 102 of 140


WK: 1 - Day: 1.1

NAME: Bill Turner


ADDRESS: 725 N. Deal Parkway
CITY: Washington
STATE: DC
ZIP: 20085
CUSTOMER_ID: 1
While this information is being retrieved, another user with a connection to this database updates Bill Turner's
address information:
SQL> UPDATE CUSTOMERS SET Address = "11741 Kingstowne Road"
WHERE Name = "Bill Turner";
As we can see, the information we retrieved earlier could be invalid if the update occurred during the middle of our
SELECT. If our application fired off a letter to be sent to Mr. Bill Turner, the address it used would be wrong.
Obviously, if the letter has already been sent, we won't be able to change the address. However, if we had used a
transaction, this data change could have been detected, and all our other operations could have been rolled back.

2. Beginning a Transaction
Transactions are quite simple to implement. We will examine the syntax used to perform transactions using the
Oracle RDBMS SQL syntax.
All database systems that support transactions must have a way to explicitly tell the system that a transaction is
beginning. (Remember that a transaction is a logical grouping of work that has a beginning and an end.) Using
Oracle, the syntax looks like this:

Syntax:
SET TRANSACTION {READ ONLY | USE ROLLBACK SEGMENT segment}
The SQL standard specifies that each database's SQL implementation must support statement-level read
consistency; that is, data must stay consistent while one statement is executing. However, in many situations data
must remain valid across a single unit of work, not just within a single statement. Oracle enables the user to specify
when the transaction will begin by using the SET TRANSACTION statement. If we wanted to examine Bill Turner's
information and make sure that the data was not changed, we could do the following:
SQL> SET TRANSACTION READ ONLY;
SQL> SELECT * FROM CUSTOMERS
WHERE NAME = 'Bill Turner';
---Do Other Operations--SQL> COMMIT;
The SET TRANSACTION READ ONLY option enables us to effectively lock a set of records until the transaction
ends. We can use the READ ONLY option with the following commands:
SELECT
LOCK TABLE
SET ROLE
ALTER SESSION
ALTER SYSTEM

3. COMMIT a Transaction
The Oracle syntax to end a transaction is as follows:

Syntax:
COMMIT [WORK]
[ COMMENT 'text'
| FORCE 'text' [, integer] ] ;
Here is the same command using Sybase syntax:

Syntax:
COMMIT (TRANSACTION | TRAN | WORK) (TRANSACTION_NAME)
The COMMIT command saves all changes made during a transaction. Executing a COMMIT statement before
beginning a transaction ensures that no errors were made and no previous transactions are left hanging.

Structure Query Language (SQL)-TCL

Page 103 of 140


WK: 1 - Day: 1.1

The following example verifies that the COMMIT command can be used by itself without receiving an error back from
the database system.
SQL> COMMIT;
SQL> SET TRANSACTION READ ONLY;
SQL> SELECT * FROM CUSTOMERS
WHERE NAME = 'Bill Turner';
---Do Other Operations--SQL> COMMIT;
An Oracle SQL use of the COMMIT statement would look like this:
SQL> SET TRANSACTION;
SQL> INSERT INTO CUSTOMERS
VALUES("John MacDowell","2000 Lake Lunge Road","Chicago", "IL", 42854, 7);
SQL> COMMIT;
SQL> SELECT * FROM CUSTOMERS;

The CUSTOMERS table.


Name

Address

City

State

Zip

Customer_ID

Bill Turner

725 N. Deal Parkway

Washington

DC

20085

John Keith

1220 Via De Luna Dr.

Jacksonville

FL

33581

Mary Rosenberg

482 Wannamaker Avenue

Williamsburg

VA

23478

David Blanken

405 N. Davis Highway

Greenville

SC

29652

Rebecca Little

7753 Woods Lane

Houston

TX

38764

Izetta Parsons

1285 Pineapple Highway

Greenville

AL

32854

John MacDowell

2000 Lake Lunge Road

Chicago

IL

42854

Remember that every COMMIT command must correspond with a previously executed SET TRANSACTION or
BEGIN TRANSACTION command. Note the errors we receive with the following statements:
SQL> INSERT INTO BALANCES VALUES (18765.42, 19073.06, 8);
SQL> COMMIT WORK;

4. ROLLBACK the Transaction


While a transaction is in progress, some type of error checking is usually performed to determine whether it is
executing successfully. We can undo our transaction even after successful completion by issuing the ROLLBACK
statement, but it must be issued before a COMMIT. The ROLLBACK statement must be executed from within a
transaction. The ROLLBACK statement rolls the transaction back to its beginning in other words, the state of the
database is returned to what it was at the transaction's beginning. The syntax for this command using Oracle is the
following:

Syntax:
ROLLBACK [WORK]
[ TO [SAVEPOINT] savepoint
| FORCE 'text' ]
As we can see, this command makes use of a transaction SAVEPOINT. An example with commands look like this:
SQL> SET TRANSACTION;
SQL> INSERT INTO CUSTOMERS VALUES
("Bubba MacDowell", "2222 Blue Lake Way", "Austin", "TX", 39874, 8);
SQL> ROLLBACK;
SQL> SELECT * FROM CUSTOMERS;

The CUSTOMERS table.


Name

Address

City

State

Zip

Customer_ID

Structure Query Language (SQL)-TCL

Page 104 of 140


WK: 1 - Day: 1.1

Bill Turner

725 N. Deal Parkway

Washington

DC

20085

John Keith

1220 Via De Luna Dr.

Jacksonville

FL

33581

Mary Rosenberg

482 Wannamaker Avenue

Williamsburg

VA

23478

David Blanken

405 N. Davis Highway

Greenville

SC

29652

Rebecca Little

7753 Woods Lane

Houston

TX

38764

Izetta Parsons

1285 Pineapple Highway

Greenville

AL

32854

John MacDowell

2000 Lake Lunge Road

Chicago

IL

42854

As we can see, the new record was not added because the ROLLBACK statement rolled the insert back.
Suppose we are writing an application for a graphical user interface, such as Microsoft Windows. We have a dialog
box that queries a database and allows the user to change values. If the user chooses OK, the database saves the
changes. If the user chooses Cancel, the changes are canceled. Obviously, this situation gives us an opportunity to
use a transaction.
When the dialog box is loaded, these SQL statements are executed:
SQL> SET TRANSACTION;
SQL> SELECT CUSTOMERS.NAME, BALANCES.CURR_BAL, BALANCES.ACCOUNT_ID
FROM CUSTOMERS, BALANCES
WHERE CUSTOMERS.NAME = "Rebecca Little"
AND CUSTOMERS.CUSTOMER_ID = BALANCES.ACCOUNT_ID;
The dialog box allows the user to change the current account balance, so we need to store this value back to the
database. When the user selects OK, the update will run.
SQL> UPDATE BALANCES SET CURR_BAL = 'new-value' WHERE ACCOUNT_ID = 6;
SQL> COMMIT;
When the user selects Cancel, the ROLLBACK statement is issued.
SQL> ROLLBACK;
The ROLLBACK statement cancels the entire transaction. When we are nesting transactions, the ROLLBACK
statement completely cancels all the transactions, rolling them back to the beginning of the outermost transaction.
If no transaction is currently active, issuing the ROLLBACK statement or the COMMIT command has no effect on the
database system. (Think of them as dead commands with no purpose.)
After the COMMIT statement has been executed, all actions with the transaction are executed. At this point it is too
late to roll back the transaction.

5. Using Transaction Savepoints


Rolling back a transaction cancels the entire transaction. But suppose we want to "semicommit" our transaction
midway through its statements. Oracle SQL allow us to save the transaction with a savepoint. From that point on, if a
ROLLBACK is issued, the transaction is rolled back to the savepoint. All statements that were executed up to the
point of the savepoint are saved. The syntax for creating a savepoint using Oracle SQL is as follows:

Syntax:
SAVEPOINT savepoint_name;
SQL>
SQL>
SQL>
SQL>
SQL>
SQL>
SQL>

SET TRANSACTION;
UPDATE BALANCES SET CURR_BAL = 25000 WHERE ACCOUNT_ID = 5;
SAVEPOINT save_it;
DELETE FROM BALANCES WHERE ACCOUNT_ID = 5;
ROLLBACK TO SAVEPOINT save_it;
COMMIT;
SELECT * FROM BALANCES;

The BALANCES table.

Average_Bal

Curr_Bal

Account_ID

Structure Query Language (SQL)-TCL

Page 105 of 140


WK: 1 - Day: 1.1

1298.53

854.22

5427.22

6015.96

211.25

190.01

73.79

25.87

1285.90

25000.00

1234.56

1543.67

345.25

348.03

1250.76

1431.26

The previous examples created a savepoint called SAVE_IT. An update was made to the database that changed the
value of the CURR_BAL column of the BALANCES table. We then saved this change as a savepoint. Following this
save, we executed a DELETE statement, but we rolled the transaction back to the savepoint immediately thereafter.
Then we executed COMMIT TRANSACTION, which committed all commands up to the savepoint. Had we executed
a ROLLBACK TRANSACTION after the ROLLBACK TRANSACTION savepoint_name command, the entire
transaction would have been rolled back and no changes would have been made.
SQL>
SQL>
SQL>
SQL>
SQL>
SQL>
SQL>

SET TRANSACTION;
UPDATE BALANCES SET CURR_BAL = 25000 WHERE ACCOUNT_ID = 5;
SAVEPOINT save_it;
DELETE FROM BALANCES WHERE ACCOUNT_ID = 5;
ROLLBACK TO SAVEPOINT save_it;
ROLLBACK;
SELECT * FROM BALANCES;

The BALANCES table.


Average_Bal

Curr_Bal

Account_ID

1298.53

854.22

5427.22

6015.96

211.25

190.01

73.79

25.87

1285.90

1473.75

1234.56

1543.67

345.25

348.03

1250.76

1431.26

Structure Query Language (SQL)- DDL & DML

Page 106 of 140


WK: 1 - Day: 1.1

1. Data Definition Language (DDL)


The CREATE TABLE, ALTER TABLE and DROP TABLE statements, which are collectively known as Data Definition
Statements. (In contrast, the SELECT, UPDATE, INSERT, and DELETE statements are often described as Data
Manipulation Statements).





Create Table
Alter Table
Drop Table

We now know much of the SQL vocabulary and have examined the SQL query in some detail, beginning with its
basic syntax. So far,we have been ignoring the process of creating databases and tables. We have assumed that
these data base objects existed currently on our system. Today we finally create these objects.
The syntax of the CREATE statements can range from the extremely simple to the complex, depending on the
options our database management system (DBMS) supports and how detailed we want our database when
designing.
Note: The examples used today were generated using Personal Oracle7. Please see the documentation for our
specific SQL implementation for any minor differences in syntax.

1.1. CREATE TABLE Statement


The process of creating a table is far more standardized than the CREATE DATABASE statement. Here's the basic
syntax for the CREATE TABLE statement:

Syntax:
CREATE TABLE
(
field1
field2
field3

table_name
datatype [ NOT NULL ],
datatype [ NOT NULL ],
datatype [ NOT NULL ]...)

A simple example of a CREATE TABLE statement follows.


SQL>

CREATE TABLE BILLS (


NAME CHAR(30),
AMOUNT NUMBER,
ACCOUNT_ID NUMBER);

Table created.

Analysis:
This statement creates a table named BILLS. Within the BILLS table are three fields: NAME, AMOUNT, and
ACCOUNT_ID. The NAME field has a data type of character and can store strings up to 30 characters long. The
AMOUNT and ACCOUNT_ID fields can contain number values only.
The following section examines components of the CREATE TABLE command.

1.1.1. Table Name


When creating a table, several constraints apply when naming the table. First, the table name can be no more than
30 characters long. Because Oracle is case insensitive, we can use either uppercase or lowercase for the individual
characters. However, the first character of the name must be a letter between A and Z. The remaining characters can
be letters or the symbols _, #, $, and @. Of course, the table name must be unique within its schema. The name also
cannot be one of the Oracle or SQL reserved words (such as SELECT).
Note: We can have duplicate table names as long as the owner or schema is different. Table names in the same
schema must be unique.

1.1.2. Field Name


The same constraints that apply to the table name also apply to the field name. However, a field name can be
duplicated within the database. The restriction is that the field name must be unique within its table. For instance,
assume that we have two tables in our database: TABLE1and TABLE2. Both of these tables could have fields called
ID. We cannot, however, have two fields within TABLE1 called ID, even if they are of different data types.

Structure Query Language (SQL)- DDL & DML

Page 107 of 140


WK: 1 - Day: 1.1

1.1.3. Field's Data Type


If we have ever programmed in any language, we are familiar with the concept of data types, or the type of data that
is to be stored in a specific field. For instance, a character data type constitutes a field that stores only character
string data. The below table shows data types supported by Oracle.

Data types supported by Oracle


Data Type Comments
CHAR

Alphanumeric data with a length between 1 and 255 characters. Spaces are padded to the right of the
value to supplement the total allocated length of the column.

DATE

Included as parts of the date are century, year, month, day, hour, minute, and second.

LONG

Variable-length alphanumeric strings up to 2 gigabytes. (See the following note.)

LONG RAW

Binary data up to 2 gigabytes. (See the following note.)

NUMBER

Numeric 0, positive or negative fixed or floating-point data.

RAW

Binary data up to 255 bytes.

ROWID

Hexadecimal string representing the unique address of a row in a table. (See the following note.)

VARCHAR2

Alphanumeric data that is variable length; this field must be between 1 and 2,000 characters long.

Note: The LONG data type is often called a MEMO data type in other database management systems. It is primarily
used to store large amounts of text for retrieval at some later time.
The LONG RAW data type is often called a binary large object (BLOB) in other database management systems. It is
typically used to store graphics, sound, or video data. Although relational database management systems were not
originally designed to serve this type of data, many multimedia systems today store their data in LONG RAW, or
BLOB, fields. The ROWID field type is used to give each record within our table a unique, no duplicating value. Many
other database systems support this concept with a COUNTER field (Microsoft Access) or an IDENTITY field (SQL
Server).

1.1.3.1. NULL Value


SQL also enables us to identify what can be stored within a column. A NULL value is almost an oxymoron, because
having a field with a value of NULL means that the field actually has no value stored in it. When building a table, most
database systems enable us to denote a column with the NOT NULL keywords. NOT NULL means the column
cannot contain any NULL values for any records in the table. Conversely, NOT NULL means that every record must
have an actual value in this column. The following example illustrates the use of the NOT NULL keywords.
SQL>

CREATE TABLE BILLS


(NAME CHAR(30) NOT NULL,AMOUNT NUMBER,ACCOUNT_ID NOT NULL);

Analysis:
In this table we want to save the name of the company we owe the money to, along with the bill's amount. If the
NAME field and/or the ACCOUNT_ID were not stored, the record would be meaningless. We would end up with a
record with a bill, but we would have no idea whom we should pay. The first statement in the next example inserts a
valid record containing data for a bill to be sent to Joe's Computer Service for $25.
SQL> INSERT INTO BILLS VALUES(Joe's Computer Service, 25, 1);
1 row inserted.
SQL> INSERT INTO BILLS VALUES("", 25000, 1);
1 row inserted.

Analysis:
Note that the second record in the preceding example does not contain a NAME value. (We might think that a
missing payee is to our advantage because the bill amount is $25,000, but we won't consider that.) If the table had

Structure Query Language (SQL)- DDL & DML

Page 108 of 140


WK: 1 - Day: 1.1

been created with a NOT NULL value for the NAME field, the second insert would have raised an error. A good rule
of thumb is that the primary key field and all foreign key fields should never contain NULL values.

1.1.3.2. Unique Fields


One of our design goals should be to have one unique column within each table. This column or field is a primary key
field. Some database management systems allow us to set a field as unique. Other database management systems,
such as Oracle and SQL Server, allow us to create a unique index on a field. This feature keeps us from not inserting
duplicate key field values into the database.
We should notice several things when choosing a key field. As we mentioned, Oracle provides a ROWID field that is
incremented for each row that is added, which makes this field by default always a unique key. ROWID fields make
excellent key fields for several reasons. First, it is much faster to join on an integer value than on an 80-character
string. Such joins result in smaller database sizes over time if we store an integer value in every primary and foreign
key as opposed to a long CHAR value. Another advantage is that we can use ROWID fields to see how a table is
organized. Also, using CHAR values leaves we open to a number of data entry problems. For instance, what would
happen if one person entered 111 First Street, another entered 111 1st Street, and yet another entered 111 First St.?
With today's graphical user environments, the correct string could be entered into a list box. When a user makes a
selection from the list box, the code would convert this string to a unique ID and save this ID to the database. Now we
can create the tables we used earlier. We will use these tables for the rest, so we will want to fill them with some
data. Use the INSERT command to load the tables with the data in Tables 9.3, 9.4, and 9.5.
SQL> CREATE DATABASE PAYMENTS;
Statement processed.
SQL> CREATE TABLE BILLS
(NAME CHAR(30) NOT NULL, AMOUNT NUMBER, ACCOUNT_ID NUMBER NOT NULL);
Table created.
SQL> CREATE TABLE BANK_ACCOUNTS
(ACCOUNT_ID NUMBER NOT NULL,TYPE CHAR(30),BALANCE NUMBER,BANK CHAR(30));
Table created.
SQL> CREATE TABLE COMPANY
(NAME CHAR(30) NOT NULL, ADDRESS CHAR(50), CITY CHAR(30), STATE CHAR(2));
Table created.
Table 9.3 Sample data for the BILLS table

Name

Amount

Account_ID

Phone Company

125

Power Company

75

Record Club

25

Software Company

250

Cable TV Company

35

Table 9.4 Sample data for the BANK_ACCOUNTS table

Account_ID Type

Balance Band

Checking

500

Money Market 1200

First Investor's

Checking

Credit Union

90

First Federal

Structure Query Language (SQL)- DDL & DML

Page 109 of 140


WK: 1 - Day: 1.1

Table 9.5 Sample data for the COMPANY table

Name

Address

City

State

Phone Company

111 1st Street

Atlanta

GA

Power Company

222 2nd Street Jacksonville

FL

Record Club

333 3rd Avenue Los Angeles

CA

Software Company 444 4th Drive

San Francisco CA

Cable TV Company 555 5th Drive

Austin

TX

1.1.4. Table Storage and Sizing


Most major RDBMS have default settings for table sizes and table locations. If we do not specify table size and
location, then the table will take the defaults. The defaults may be very undesirable, especially for large tables. The
default sizes and locations will vary among the implementations. Here is an example of a CREATE TABLE statement
with a storage clause (from Oracle).
SQL>

CREATE TABLE TABLENAME


(COLUMN1 CHAR NOT NULL, COLUMN2 NUMBER, COLUMN3 DATE)
TABLESPACE TABLESPACE NAME
STORAGE
INITIAL SIZE,
NEXT SIZE,
MINEXTENTS value,
MAXEXTENTS value,
PCTINCREASE value);

Table created.

Analysis:
In Oracle we can specify a tablespace in which we want the table to reside. A decision is usually made according to
the space available, often by the database administrator (DBA). INITIAL SIZE is the size for the initial extent of the
table (the initial allocated space). NEXT SIZE is the value for any additional extents the table may take through
growth. MINEXTENTS and MAXEXTENTS identify the minimum and maximum extents allowed for the table, and
PCTINCREASE identifies the percentage the next extent will be increased each time the table grows, or takes
another extent.

1.1.5. Creating a Table from an Existing Table


The most common way to create a table is with the CREATE TABLE command. However, some database
management systems provide an alternative method of creating tables, using the format and data of an existing table.
This method is useful when we want to select the data out of a table for temporary modification. It can also be useful
when we have to create a table similar to the existing table and fill it with similar data. (We won't have to reenter all
this information.) The syntax for Oracle follows.

Syntax:
SQL> CREATE TABLE NEW_TABLE(FIELD1, FIELD2, FIELD3)
AS (SELECT FIELD1, FIELD2, FIELD3
FROM OLD_TABLE <WHERE...>
This syntax allows us to create a new table with the same data types as those of the fields that are selected from the
old table. It also allows us to rename the fields in the new table by giving them new names.
SQL> CREATE TABLE NEW_BILLS(NAME, AMOUNT, ACCOUNT_ID)
AS (SELECT * FROM BILLS WHERE AMOUNT < 50);
Table created.

Analysis:

Structure Query Language (SQL)- DDL & DML

Page 110 of 140


WK: 1 - Day: 1.1

The preceding statement creates a new table (NEW_BILLS) with all the records from the BILLS table that have an
AMOUNT less than 50. Some database systems also allow us to use the following syntax:

Syntax:
SQL> INSERT NEW_TABLE
SELECT <field1, field2... | *>
FROM OLD_TABLE <WHERE...>
The preceding syntax would create a new table with the exact field structure and data found in the old table. Using
SQL Server's Transact-SQL language in the following example illustrates this technique.
SQL> INSERT NEW_BILLS
SQL> SELECT * FROM BILLS WHERE AMOUNT < 50

1.2. ALTER TABLE Statement


Many times our database design does not account for everything it should. Also, requirements for applications and
databases are always subject to change. The ALTER TABLE statement enables the database administrator or
designer to change the structure of a table after it has been created.
The ALTER TABLE command enables us to do two things:




Add a column to an existing table


Modify a column that already exists

The syntax for the ALTER TABLE statement is as follows:

Syntax:
SQL> ALTER TABLE table_name
<ADD column_name data_type; | MODIFY column_name data_type;>
The following command changes the NAME field of the BILLS table to hold 40 characters:
SQL> ALTER TABLE BILLS
MODIFY NAME CHAR(40);
Table altered.
Note: We can increase or decrease the length of columns; however, we can not decrease a column's length if the
current size of one of its values is greater than the value we want to assign to the column length.
Here's a statement to add a new column to the NEW_BILLS table:
SQL> ALTER TABLE NEW_BILLS
ADD COMMENTS CHAR(80);
Table altered.

Analysis:
This statement would add a new column named COMMENTS capable of holding 80 characters. The field would be
added to the right of all the existing fields.
Several restrictions apply to using the ALTER TABLE statement. We cannot use it to add or delete fields from a
database. It can change a column from NOT NULL to NULL, but not necessarily the other way around. A column
specification can be changed from NULL to NOT NULL only if the column does not contain any NULL values. To
change a column from NOT NULL to NULL, use the following syntax:

Syntax:
SQL> ALTER TABLE table_name MODIFY (column_name data_type NULL);
To change a column from NULL to NOT NULL, we might have to take several steps:
1.

Determine whether the column has any NULL values.

2.

Deal with any NULL values that we find. (Delete those records, update the column's value, and so on.)

Structure Query Language (SQL)- DDL & DML

3.

Page 111 of 140


WK: 1 - Day: 1.1

Issue the ALTER TABLE command.

Note: Some database management systems allow the use of the MODIFY clause; others do not. Still others have
added other clauses to the ALTER TABLE statement. In Oracle, we can even alter the table's storage parameters.
Check the documentation of the system we are using to determine the implementation of the ALTER TABLE
statement.

1.3. DROP TABLE Statement


SQL provides a command to completely remove a table from a database. The DROP TABLE command deletes a
table along with all its associated views and indexes. After this command has been issued, there is no turning back.
The most common use of the DROP TABLE statement is when we have created a table for temporary use. When we
have completed all operations on the table that we planned to do, issue the DROP TABLE statement with the
following syntax:

Syntax:
SQL> DROP TABLE table_name;
Here's how to drop the NEW_BILLS table:
SQL> DROP TABLE NEW_BILLS;
Table dropped.

Analysis:
Note the absence of system prompts. This command did not ask Are we sure? (Y/N). After the DROP TABLE
command is issued, the table is permanently deleted.
Warning: If we issue
SQL> DROP TABLE NEW_BILLS;
We could be dropping the incorrect table. When dropping tables, we should always use the owner or schema name.
The recommended syntax is
SQL> DROP TABLE OWNER.NEW_BILLS;
We are stressing this syntax because we once had to repair a production database from which the wrong table had
been dropped. The table was not properly identified with the schema name. Restoring the database was an eighthour job, and we had to work until well past midnight.

2. Data Manipulation Language (DML)






How to manipulate data using the INSERT, UPDATE, and DELETE commands
The importance of using the WHERE clause when we are manipulating data
The basics of importing and exporting data from foreign data sources

Introduction to Data Manipulation Statements


Up to this point we have learned how to retrieve data from a database using every selection criterion imaginable.
After this data is retrieved, we can use it in an application program or edit it. However, we may have wondered how to
enter data into the database in the first place. We may also be wondering what to do with data that has been edited.
We discuss three SQL statements that enable we to manipulate the data within a database's table. The three
statements are as follows:





The INSERT statement


The UPDATE statement
The DELETE statement

We may have used a PC-based product such as Access, dBASE IV, or FoxPro to enter our data in the past. These
products come packaged with excellent tools to enter, edit, and delete records from databases. One reason that SQL
provides data manipulation statements is that it is primarily used within application programs that enable the user to
edit the data using the application's own tools. The SQL programmer needs to be able to return the data to the
database using SQL. In addition, most large-scale database systems are not designed with the database designer or

Structure Query Language (SQL)- DDL & DML

Page 112 of 140


WK: 1 - Day: 1.1

programmer in mind. Because these systems are designed to be used in high-volume, multi-user environments, the
primary design emphasis is placed on the query optimizer and data retrieval engines.

2.1. INSERT Statement


The INSERT statement enables us to enter data into the database. It can be broken down into two statements:
INSERT...VALUES
And
INSERT...SELECT

2.1.1. The INSERT...VALUES Statement


The INSERT...VALUES statement enters data into a table one record at a time. It is useful for small operations that
deal with just a few records. The syntax of this statement is as follows:

Syntax:
SQL> INSERT INTO table_name
(col1, col2...)
VALUES(value1, value2...)
The basic format of the INSERT...VALUES statement adds a record to a table using the columns we give it and the
corresponding values we instruct it to add. We must follow three rules when inserting data into a table with the
INSERT...VALUES statement:





The values used must be the same data type as the fields they are being added to.
The data's size must be within the column's size. For instance, we cannot add an 80-character string to a 40character column.
The data's location in the VALUES list must correspond to the location in the column list of the column it is
being added to. (That is, the first value must be entered into the first column, the second value into the
second column, and so on.)

Example 1
Assume we have a COLLECTION table that lists all the important stuff we have collected. We can display the table's
contents by writing
SQL> SELECT * FROM COLLECTION;
ITEM
WORTH REMARKS
-------------------- --------- ---------------------------NBA ALL STAR CARDS
300 SOME STILL IN BIKE SPOKES
MALIBU BARBIE
150 TAN NEEDS WORK
STAR WARS GLASS
5.5 HANDLE CHIPPED
LOCK OF SPOUSES HAIR
1 HASN'T NOTICED BALD SPOT YET
If we wanted to add a new record to this table, we would write
SQL> INSERT INTO COLLECTION
(ITEM, WORTH, REMARKS)
VALUES('SUPERMANS CAPE', 250.00, 'TUGGED ON IT');
1 row created.
We can execute a simple SELECT statement to verify the insertion:
SQL> SELECT * FROM COLLECTION;
ITEM
WORTH REMARKS
-------------------- --------- ---------------------------NBA ALL STAR CARDS
300 SOME STILL IN BIKE SPOKES
MALIBU BARBIE
150 TAN NEEDS WORK
STAR WARS GLASS
5.5 HANDLE CHIPPED
LOCK OF SPOUSES HAIR
1 HASN'T NOTICED BALD SPOT YET
SUPERMANS CAPE
250 TUGGED ON IT

Structure Query Language (SQL)- DDL & DML

Page 113 of 140


WK: 1 - Day: 1.1

Analysis:
The INSERT statement does not require column names. If the column names are not entered, SQL lines up the
values with their corresponding column numbers. In other words, SQL inserts the first value into the first column, the
second value into the second column, and so on.

Example 2
The following statement inserts the values from Example 1 into the table:
SQL> INSERT INTO COLLECTION VALUES
('STRING',1000.00,'SOME DAY IT WILL BE VALUABLE');
1 row created.

Analysis:
By issuing the same SELECT statement as we did in Example 1, we can verify that the insertion worked as expected:
SQL> SELECT * FROM COLLECTION;
ITEM
WORTH REMARKS
-------------------- --------- ---------------------------NBA ALL STAR CARDS
300 SOME STILL IN BIKE SPOKES
MALIBU BARBIE
150 TAN NEEDS WORK
STAR WARS GLASS
5.5 HANDLE CHIPPED
LOCK OF SPOUSES HAIR
1 HASN'T NOTICED BALD SPOT YET
SUPERMANS CAPE
250 TUGGED ON IT
STRING
1000 SOME DAY IT WILL BE VALUABLE
6 rows selected.

2.1.1.1. Inserting NULL Values


We learn how to create tables using the CREATE TABLE statement. For now, all we need to know is that when a
column is created, it can have several different limitations placed upon it. One of these limitations is that the column
should (or should not) be allowed to contain NULL values. A NULL value means that the value is empty. It is neither a
zero, in the case of an integer, nor a space, in the case of a string. Instead, no data at all exists for that record's
column. If a column is defined as NOT NULL (that column is not allowed to contain a NULL value), we must insert a
value for that column when using the INSERT statement. The INSERT is canceled if this rule is broken, and we
should receive a descriptive error message concerning our error.
Warning: We could insert spaces for a null column, but these spaces will be treated as a value. NULL simply means
nothing is there.
SQL> INSERT INTO collection VALUES
('SPORES MILDEW FUNGUS', 50.00, ' ');
1 row inserted.

Analysis:
Using '' instead of NULL inserted a space in the collection table. We then can select the space.
SQL> SELECT *
FROM collection
WHERE remarks = ' ';

ITEM
WORTH
REMARKS
--------------------------- -------- --------SPORES MILDEW FUNGUS
50.00
1 row selected.

Structure Query Language (SQL)- DDL & DML

Page 114 of 140


WK: 1 - Day: 1.1

Analysis:
The resulting answer comes back as if a NULL is there. With the output of character fields, it is impossible to tell the
difference between a null value and a mere space.
Assume the column REMARKS in the preceding table has been defined as NOT NULL. Typing
SQL> INSERT INTO COLLECTION
VALUES('SPORES MILDEW FUNGUS',50.00,NULL);
Produces the following error:
INSERT INTO COLLECTION
*
ERROR at line 1:
ORA-01400: mandatory (NOT NULL) column is missing or NULL during insert
Note: Number data types do not require quotes; NULL does not require quotes; character data types do require
quotes.

2.1.1.2. Inserting Unique Values


Many database management systems also allow us to create a UNIQUE column attribute. This attribute means that
within the current table, the values within this column must be completely unique and cannot appear more than once.
This limitation can cause problems when inserting or updating values into an existing table, as the following exchange
demonstrates:
SQL> INSERT INTO COLLECTION VALUES('STRING', 50, 'MORE STRING');
INSERT INTO COLLECTION VALUES('STRING', 50, 'MORE STRING')
*
ERROR at line 1:
ORA-00001: unique constraint (PERKINS.UNQ_COLLECTION_ITEM) violated

Analysis:
In this example we tried to insert another ITEM called STRING into the COLLECTION table. Because this table was
created with ITEM as a unique value, it returned the appropriate error. ANSI SQL does not offer a solution to this
problem, but several commercial implementations include extensions that would allow us to use something like the
following:
IF NOT EXISTS (SELECT * FROM COLLECTION WHERE NAME = 'STRING'
INSERT INTO COLLECTION VALUES('STRING', 50, 'MORE STRING')
This particular example is supported in the Sybase system.
A properly normalized table should have a unique, or key, field. This field is useful for joining data between tables,
and it often improves the speed of our queries when using indexes.
Note: Here's an INSERT statement that inserts a new employee into a table:
SQL> INSERT INTO employee_tbl VALUES
('300500177', 'SMITHH', 'JOHN');
1 row inserted.

2.1.2. The INSERT...SELECT Statement


The INSERT...VALUES statement is useful when adding single records to a database table, but it obviously has
limitations. Would we like to use it to add 25,000 records to a table? In situations like this, the INSERT...SELECT
statement is much more beneficial. It enables the programmer to copy information from a table or group of tables into
another table. We will want to use this statement in several situations. Lookup tables are often created for
performance gains. Lookup tables can contain data that is spread out across multiple tables in multiple databases.
Because multiple-table joins are slower to process than simple queries, it is much quicker to execute a SELECT
query against a lookup table than to execute a long, complicated joined query. Lookup tables are often stored on the
client machines in client/server environments to reduce network traffic.

Structure Query Language (SQL)- DDL & DML

Page 115 of 140


WK: 1 - Day: 1.1

Many database systems also support temporary tables. Temporary tables exist for the life of our database connection
and are deleted when our connection is terminated. The INSERT...SELECT statement can take the output of a
SELECT statement and insert these values into a temporary table.
Here is an example:
SQL> INSERT INTO tmp_tbl
SELECT * FROM TABLE;
19,999 rows inserted.

Analysis:
We are selecting all the rows that are in table and inserting them into tmp_tbl.
Note: Not all database management systems support temporary tables. Check the documentation for the specific
system we are using to determine if this feature is supported.
The syntax of the INSERT...SELECT statement is as follows:

Syntax:
SQL> INSERT INTO table_name
(col1, col2...)
SELECT col1, col2...
FROM tablename
WHERE search_condition
Essentially, the output of a standard SELECT query is then input into a database table. The same rules that applied
to the INSERT...VALUES statement apply to the INSERT...SELECT statement. To copy the contents of the
COLLECTION table into a new table called INVENTORY, execute the set of statements in Example 3.

Example 3
This example creates the new table INVENTORY.
SQL> CREATE TABLE INVENTORY(ITEM CHAR(20),COST NUMBER,
ROOM CHAR(20),REMARKS CHAR(40));
Table created.
The following INSERT fills the new INVENTORY table with data from COLLECTION.
SQL> INSERT INTO INVENTORY (ITEM, COST, REMARKS)
SELECT ITEM, WORTH, REMARKS
FROM COLLECTION;
6 rows created.
We can verify that the INSERT works with this SELECT statement:
SQL> SELECT * FROM INVENTORY;
ITEM
COST ROOM
-------------------- --------- -------NBA ALL STAR CARDS
300
MALIBU BARBIE
150
STAR WARS GLASS
5.5
LOCK OF SPOUSES HAIR
1
SUPERMANS CAPE
250
STRING
1000

REMARKS
---------------------------SOME STILL IN BIKE SPOKES
TAN NEEDS WORK
HANDLE CHIPPED
HASN'T NOTICED BALD SPOT YET
TUGGED ON IT
SOME DAY IT WILL BE VALUABLE

6 rows selected.
Note: The data appears to be in the table; however, the transaction is not finalized until a COMMIT is issued. The
transaction can be committed either by issuing the COMMIT command or by simply exiting.

Analysis:

Structure Query Language (SQL)- DDL & DML

Page 116 of 140


WK: 1 - Day: 1.1

We have successfully, and somewhat painlessly, moved the data from the COLLECTION table to the new
INVENTORY table!
The INSERT...SELECT statement requires us to follow several new rules:





The SELECT statement cannot select rows from the table that is being inserted into.
The number of columns in the INSERT INTO statement must equal the number of columns returned from the
SELECT statement.
The data types of the columns in the INSERT INTO statement must be the same as the data types of the
columns returned from the SELECT statement.

Another use of the INSERT...SELECT statement is to back up a table that we are going to drop, truncate for
repopulation, or rebuild. The process requires us to create a temporary table and insert data that is contained in our
original table into the temporary table by selecting everything from the original table. For example:
SQL> INSERT INTO copy_table
SELECT * FROM original_table;
Now we can make changes to the original table with a clear conscience.
Note: Later today we learn how to input data into a table using data from another database format. Nearly all
businesses use a variety of database formats to store data for their organizations. The applications programmer is
often expected to convert these formats, and we will learn some common methods for doing just that.

2.2. UPDATE Statement


The purpose of the UPDATE statement is to change the values of existing records. The syntax is

Syntax:
SQL> UPDATE table_name
SET columnname1 = value1
[, columname2 = value2]...
WHERE search_condition
This statement checks the WHERE clause first. For all records in the given table in which the WHERE clause
evaluates to TRUE, the corresponding value is updated.

Example 4
This example illustrates the use of the UPDATE statement:
SQL> UPDATE COLLECTION
SET WORTH = 900
WHERE ITEM = 'STRING';
1 row updated.
To confirm the change, the query
SQL> SELECT * FROM COLLECTION
WHERE ITEM = 'STRING';
ITEM
WORTH REMARKS
-------------------- --------- -----------------------------STRING
900 SOME DAY IT WILL BE VALUABLE
Here is a multiple-column update:
SQL> UPDATE collection
SET worth = 900, item = ball
WHERE item = 'STRING';
1 row updated.
Note: Our implementation might use a different syntax for multiple-row updates. Notice in the set that 900 do not have
quotes, because it is a numeric data type. On the other hand, String is a character data type, which requires the
quotes.

Example 5

Structure Query Language (SQL)- DDL & DML

Page 117 of 140


WK: 1 - Day: 1.1

If the WHERE clause is omitted, every record in the COLLECTION table is updated with the value given.
SQL> UPDATE COLLECTION
SET WORTH = 555;
6 rows updated.
Performing a SELECT query shows that every record in the database was updated with that value:
SQL> SELECT * FROM COLLECTION;
ITEM
WORTH REMARKS
-------------------- --------- -----------------------------NBA ALL STAR CARDS
555 SOME STILL IN BIKE SPOKES
MALIBU BARBIE
555 TAN NEEDS WORK
STAR WARS GLASS
555 HANDLE CHIPPED
LOCK OF SPOUSES HAIR
555 HASN'T NOTICED BALD SPOT YET
SUPERMANS CAPE
555 TUGGED ON IT
STRING
555 SOME DAY IT WILL BE VALUABLE
6 rows selected.
We, of course, should check whether the column we are updating allows unique values only.
Warning: If we omit the WHERE clause from the UPDATE statement, all records in the given table are updated.
Some database systems provide an extension to the standard UPDATE syntax. SQL Server's Transact-SQL
language, for instance, enables programmers to update the contents of a table based on the contents of several other
tables by using a FROM clause. The extended syntax looks like this:

Syntax:
SQL> UPDATE table_name
SET columnname1 = value1
[, columname2 = value2]...
FROM table_list
WHERE search_condition

Example 6
Here's an example of the extension:
SQL> UPDATE COLLECTION
SET WORTH = WORTH * 0.005;
SQL> SELECT * FROM COLLECTION;
ITEM
WORTH REMARKS
-------------------- -------- ---------------------------NBA ALL STAR CARDS
2.775 SOME STILL IN BIKE SPOKES
MALIBU BARBIE
2.775 TAN NEEDS WORK
STAR WARS GLASS
2.775 HANDLE CHIPPED
LOCK OF SPOUSES HAIR
2.775 HASN'T NOTICED BALD SPOT YET
SUPERMANS CAPE
2.775 TUGGED ON IT
STRING
2.775 SOME DAY IT WILL BE VALUABLE
6 rows selected.

Analysis:
This syntax is useful when the contents of one table need to be updated following the manipulation of the contents of
several other tables. Keep in mind that this syntax is nonstandard and that we need to consult the documentation for
our particular database management system before we use it.
The UPDATE statement can also update columns based on the result of an arithmetic expression. When using this
technique, remember the requirement that the data type of the result of the expression must be the same as the data
type of the field that is being modified. Also, the size of the value must fit within the size of the field that is being
modified.

Structure Query Language (SQL)- DDL & DML

Page 118 of 140


WK: 1 - Day: 1.1

Two problems can result from the use of calculated values: truncation and overflow. Truncation results when the
database system converts a fractional number to an integer, for instance. Overflow results when the resulting value is
larger than the capacity of the modified column, which will cause an error to be returned by our database system.
Note: Some database systems handle the overflow problem for us. Oracle converts the number to exponential
notation and presents the number that way. We should keep this potential error in mind when using number data
types.

2.3. DELETE Statement


In addition to adding data to a database, we will also need to delete data from a database. The syntax for the
DELETE statement is

Syntax:
SQL> DELETE FROM tablename
WHERE condition
The first thing we will probably notice about the DELETE command is that it doesn't have a prompt. Users are
accustomed to being prompted for assurance when, for instance, a directory or file is deleted at the operating system
level. Are we sure? (Y/N) is a common question asked before the operation is performed. Using SQL, when we
instruct the DBMS to delete a group of records from a table, it obeys our command without asking. That is, when we
tell SQL to delete a group of records, it will really do it!
Depending on the use of the DELETE statements WHERE clause, SQL can do the following:






Delete single rows


Delete multiple rows
Delete all rows
Delete no rows

Here are several points to remember when using the DELETE statement:





The DELETE statement cannot delete an individual field's values (use UPDATE instead). The DELETE
statement deletes entire records from a single table.
Like INSERT and UPDATE, deleting records from one table can cause referential integrity problems within
other tables. Keep this potential problem area in mind when modifying data within a database.
Using the DELETE statement deletes only records, not the table itself. Use the DROP TABLE statement to
remove an entire table.

Example 7
This example shows us how to delete all the records from COLLECTION where WORTH is less than 275.
SQL> DELETE FROM COLLECTION
WHERE WORTH < 275;
4 rows deleted.
The result is a table that looks like this:
SQL> SELECT * FROM COLLECTION;
ITEM
WORTH REMARKS
-------------------- --------- -----------------------------NBA ALL STAR CARDS
300 SOME STILL IN BIKE SPOKES
STRING
1000 SOME DAY IT WILL BE VALUABLE
Warning: Like the UPDATE statement, if we omit a WHERE clause from the DELETE statement, all rows in that
particular table will be deleted.
Example 8 uses all three data manipulation statements to perform a set of database operations.
This example inserts some new rows into the COLLECTION table we used earlier today.
SQL> INSERT INTO COLLECTION
VALUES('CHIA PET', 5,'WEDDING GIFT');
1 row created.

Structure Query Language (SQL)- DDL & DML

Page 119 of 140


WK: 1 - Day: 1.1

SQL> INSERT INTO COLLECTION


VALUES('TRS MODEL III', 50, 'FIRST COMPUTER');
1 row created.
Now create a new table and copy this data to it:
SQL> CREATE TABLE TEMP (NAME CHAR(20),VALUE NUMBER,REMARKS CHAR(40));
Table created.
SQL> INSERT INTO TEMP(NAME, VALUE, REMARKS)
SELECT ITEM, WORTH, REMARKS
FROM COLLECTION;
4 rows created.
SQL> SELECT * FROM TEMP;
NAME
VALUE REMARKS
-------------------- --------- -----------------------------NBA ALL STAR CARDS
300 SOME STILL IN BIKE SPOKES
STRING
1000 SOME DAY IT WILL BE VALUABLE
CHIA PET
5 WEDDING GIFT
TRS MODEL III
50 FIRST COMPUTER
Now change some values:
SQL> UPDATE TEMP
SET VALUE = 100
WHERE NAME = 'TRS MODEL III';
1 row updated.
SQL> UPDATE TEMP
SET VALUE = 8
WHERE NAME = 'CHIA PET';
1 row updated.
SQL> SELECT * FROM TEMP;
NAME
VALUE REMARKS
-------------------- --------- ---------------------------NBA ALL STAR CARDS
300 SOME STILL IN BIKE SPOKES
STRING
1000 SOME DAY IT WILL BE VALUABLE
CHIA PET
8 WEDDING GIFT
TRS MODEL III
100 FIRST COMPUTER
And update these values back to the original table:
SQL> INSERT COLLECTION
SQL> SELECT * FROM TEMP;
SQL> DROP TABLE TEMP;

Analysis:
The DROP TABLE and CREATE TABLE statements are discussed in greater detail. For now, these statements
basically do what their names suggest. CREATE TABLE builds a new table with the format we give it, and DROP
TABLE deletes the table. Keep in mind that DROP TABLE permanently removes a table, whereas DELETE FROM
<TableName> removes only the records from a table.
To check what we have done, select out the records from the COLLECTION table. We will see that the changes we
made now exist in the COLLECTION table.
SQL> SELECT * FROM COLLECTION;

Structure Query Language (SQL)- DDL & DML

Page 120 of 140


WK: 1 - Day: 1.1

NAME
VALUE REMARKS
-------------------- -------- ---------------------------NBA ALL STAR CARDS
300 SOME STILL IN BIKE SPOKES
STRING
1000 SOME DAY IT WILL BE VALUABLE
CHIA PET
8 WEDDING GIFT
TRS MODEL III
100 FIRST COMPUTER

Analysis:
The previous example used all three data manipulation commands--INSERT, UPDATE, and DELETE--to perform a
set of operations on a table. The DELETE statement is the easiest of the three to use.
Warning: Always keep in mind that any modifications can affect the referential integrity of our database. Think
through all our database editing steps to make sure that we have updated all tables correctly.

Structure Query Language (SQL)- Security and Access

Page 121 of 140


WK: 1 - Day: 1.1

Security and Access


1. Introduction
Data Control Statements are used for authorizing data access, in order to preserve the security of the data within the
database. These statements can ensure that unauthorized users dont change or view data accidentally or
deliberately. Data access authorizations are provided using the GRANT statement.
The SQL standard doesnt specify any method of removing authorizations previously granted. Fortunately, most SQL
implementations have standardized on the REVOKE statement with consistent syntax. To complete the needs of the
maintenance of security and access at any installation, enhancements have been provided by SQL statements.

2. The Concept of USER


In the SQL environment, every user is identified by what is known as an Authorization Identifier. All data access
authorization is associated with a user through the users authorization identifier.
In most RDBMSs, a user has to log-on to the RDBMS to be able to use any of its facilities. During this log-on process,
the authorization identifier is made known to the RDBMS and subsequent activities that the user can undertake on
the database depend upon the data access authorization associated with the authorization identifier. The process of
log-on itself varies from RDBMS to RDBMS as SQL does not lay down any standard guidelines. The SQL standard
assumes that whenever an SQL command is submitted there is an Authorization Identifier associated with it.
In most RDBMSs, the log-on process requires the user to specify the users authorization identifier along with a
password. The authorization identifier is also called the usercode or log-on id. Facilities are normally available for
a user to change his or her password.
RDBMSs also provide for different types of users, whose access to RDBMS facilities vary. For Example.




A super-user (a user with DBA authority) can create new users, insert, update and delete from table, remove
existing users, create base tables and views using any table. In essence, a super-user can use any of the
facilities in the RDBMS. This user can create other users (including users of type DBA), and also change the
password of the default super-user.
Users with an authorization to resource facilities of the RSBMS can create tables and views (objects) and
give privileges on them to other users. These users do not have access to any objects (tables and views)
unless they are owned by them, or access to them has been explicitly granted.
Users with an authorization to only connect facilities cannot create new base tables. They can however,
access exiting base tables and views provided access to these tables and views has been explicitly granted.
These users can create views using the tables and views which are accessible to them.

3. Schemas and Qualifiers


Table creation is a part of schema creation as given in the following example
SQL> CREATE SCHEMA AUTHORIZATION USER1;
SQL> CREATE TABLE DEPARTMENT
(DEPT_NO NUMBER(3) NOT NULL,
DEPT_NAME VARCHAR2(30),
LOC VARCHAR2(30),
PRIMARY KEY (DEPT_NO));
SQL> CREATE TABLE EMPLOYEE
(EMP_NO NUMBER(5) NOT NULL PRIMARY KEY,
EMP_SURNAME VARCHAR2(35) NOT NULL,
EMP_FNAME VARCHAR2(35) NOT NULL,
DEPT_NO NUMBER(3) NOT NULL,
SAL NUMBER(7,2),
UNIQUE(EMP_SURNAME, EMP_FNAME),
CHECK(DEPT_NO<20 OR SAL > 5000),
FOREIGN KEY (DEPT_NO) REFERENCES DEPARTMENT(DEPT_NO));
Note: If we dont specify column name in references table (DEPARTMENT) by default it will take PRIMARY KEY
column of references table (DEPARTMENT).

Structure Query Language (SQL)- Security and Access

Page 122 of 140


WK: 1 - Day: 1.1

A scheme is a piece of the database that is owned by some specific user. The complete database definition will
typically consist of multiple schemas. The CREATE SCHEMA contains table creation, view and grant operations.
Important aspects associated with schema definition are:








AUTHORIZATION USER1 specifies that user USER1 is the owner of this schema.
The CRAETE SCHEMA can contain many (or zero) statements for creating table and/or statements for
creating views and/or statements for granting privileges to other users.
USER1 is said to own all the tables and views created in this schema.
A user is not allowed to own more than one schema.
A schema cannot be owned by more than one user.
Tables and views in different schemas can have the same (unqualified) name. Hence USER1.EMPLOYEE
and USER2.EMPLOYEE refer to two different tables.

4. Object Level Authorization Privileges


Object level privileges control what a user can do with respect to a table and columns in the table. The standard sets
of object level privileges are:
SELECT

A user can perform SELECT operations on this table.

INSERT

A user can INSERT rows into this table.

UPDATE

A user can UPDATE rows on this table. If a list of columns (Optional) is specified with this privilege,
then the user can update values in those columns alone.

DELETE

A user can DELETE rows from this table.

REFERENCE

A user can define a foreign key that uses one or more columns of this table as a primary key. The
privilege can be restricted to certain columns by (optionally) providing the column list.

5. GRANT Statement
The Syntax of the GRANT command which is used to provide data access is:





SQL> GRANT <privilege specification> ON <table> TO


<grantee list>
[WITH GRANT OPTION]
<privilege specification> is either a comma delimited list of specific privileges (SELECT, INSERT, UPDATE,
DELETE, REFERENCES) with an optional parenthesized comma delimited list of column names in case of
UPDATE and REFERENCE or the word[s] ALL [PRIVILEGES].
<table> is a base table or a view.
<grantee> is either a comma delimited list of valid authorization identifiers or the word PUBLIC.

The GRANT command is further explained with the help of examples which assumes a user with authorization
identifier USER3 and a table RESIGNATIONS (columns : SUBMITTED_TO, RESIGNED_AS, STATED_REASON
and ACTUAL_REASON).
SQL> GRANT INSERT ON RESIGNATRATION TO USER3;
Will all USER3 to ass rows to the RESIGNATIONS table.
GRANT of multiple privileges can be combined as follows as:
SQL> GRANT SELECT, INSERT, DELETE, UPDATE, REFERENCES ON RESIGNATION TO USER3;
Since the above SQL statement gives USER3 a free hand with RESIGNATIONS, it is equivalent to:
SQL> GRANT ALL PRIVILEGES ON RESIGNATION TO USER3;

OR
SQL> GRANT ALL ON RESIGNATIONS TO USER3;

Structure Query Language (SQL)- Security and Access

Page 123 of 140


WK: 1 - Day: 1.1

5.1. WITH GRANT OPTION


The implicit assumption till now has been that the current user (who has been issuing all those GRANT statements)
has the right to grant the privileges on RESIGNATIONS to others. The user who creates a table (base table or view)
automatically has the right to grant all the privileges.
The WITH GRANT OPTION clause passes this right to grant privileges on a table, to other users. Once a user has
the right to grant a privilege (whether by virtue of being the creator or of having been passed on the right through the
WITH GRANT OPTION), the user can further pass on the privilege to other users.
SQL> GRANT SELECT ON RESIGNATIONS TO USER3
WITH GRANT OPTION;
Not only allows USER3 to SELECT from the table but also to GRANT the SELECT privilege to other.

6. The REVOKE Statement


The base standard of SQL does not specify any means of taking away privileges once they have been granted to
users. Fortunately, most implementations of SQL have standardized on the REVOKE command.
SQL> REVOKE SELECT ON RESIGNATIONS FROM USER3;
This just the opposite of the GRANT statement. The <privilege specification> and <grantee list> are to be used just
as in the GRANT statement. The lack of standardization has given rise to one ambiguity. In case a USER3 had been
given a privilege WITH GRANT OPTION, an USER3 in turn passed the privilege to USER3 automatically REVOKE
the privilege from USER3? Though logically this should be so, there may be difference in this aspect across
implementation of SQL.

Structure Query Language (SQL)- Integrity Constraints

Page 124 of 140


WK: 1 - Day: 1.1

Integrity Constraints
Data integrity allows defining certain data quality requirements that the data in the database needs to meet. If a user
tries to insert data that doesn't meet these requirements, Oracle will not allow so.

1. Constraint types
There are five integrity constraints in Oracle.







Primary Key
Foreign Key
Unique Key
Not Null
Check

1.1. Primary Key


On a technical level, a PRIMARY KEY combines a unique and a NOT NULL constraint. Additionally, a table can have
at most one primary key. After creating a primary key, it can be referenced by a FOREIGN KEY.
SQL> CREATE TABLE ri_primary_key (
A NUMBER PRIMARY KEY,
B NUMBER
);
Primary keys can explicitly be named. The following create table statement creates a table with a primary key whose
name is pk_name.
SQL> CREATE TABLE ri_primary_key_1 (
A NUMBER,
B NUMBER,
C NUMBER,
CONSTRAINT pk_name PRIMARY KEY (A, B)
);

1.2. Foreign Key


A foreign key constraint (also called referential integrity constraint) on a column ensures that the value in that column
is found in the primary key of another table.
If a table has a foreign key that references a table, that referenced table can be dropped with a drop table. cascade
constraints.
It is not possible to establish a foreign key on a global temporary table. If tried, Oracle issues an ORA-14455: attempt
to create referential integrity constraint on temporary table.

1.3. Unique Key


The unique constraint doesn't allow duplicate values in a column. If the unique constraint encompasses two or more
columns, no two equal combinations are allowed.
SQL> CREATE TABLE ri_unique (
A NUMBER UNIQUE,
B NUMBER
);
However, if a column is not explicitly defined as NOT NULL, nulls can be inserted multiple times:
SQL>
SQL>
SQL>
SQL>
SQL>
SQL>

INSERT
INSERT
INSERT
INSERT
INSERT
INSERT

INTO
INTO
INTO
INTO
INTO
INTO

ri_unique
ri_unique
ri_unique
ri_unique
ri_unique
ri_unique

VALUES
VALUES
VALUES
VALUES
VALUES
VALUES

(4,5);
(2,1);
(9,8);
(6,9);
(null,9);
(null,9);

Structure Query Language (SQL)- Integrity Constraints

Page 125 of 140


WK: 1 - Day: 1.1

Now: trying to insert the number 2 again into a:


SQL> INSERT INTO ri_unique VLAUES (2,7);
This statement issues a ORA-00001: unique constraint (RENE.SYS_C001463 violated). Every constraint, by the way,
has a name. In this case, the name is: RENE.SYS_C001463.
In order to remove that constraint, an ALTER TABLE ... DROP CONSTRAINT ... is needed:
SQL> ALTER TABLE ri_unique DROP CONSTRAINT sys_c001463;
Of course, it is also possible to add a unique constraint on an existing table:
SQL> ALTER TABLE ri_unique ADD CONSTRAINT uq_ri_b UNIQUE (b);
A unique constraint can be extended over multiple columns:
SQL> CREATE TABLE ri_3 (
A NUMBER,
B NUMBER,
C NUMBER,
UNIQUE (A,B)
);
It is possible to name the constraint. The following example creates a unique constraint on the columns a and b and
names the constraint uq_ri_3.
SQL> CREATE TABLE ri_3 (
A NUMBER,
B NUMBER,
C NUMBER,
CONSTRAINT uq_ri_3 UNIQUE (A,B)
);

1.4. Not Null


A column in a table can be specified NOT NULL. It's not possible to insert a NULL in such a column. The default is
null. So, in the following create table statement, a null can be inserted into the column named c.
SQL> CREATE TABLE ri_not_null(
A NUMBER NOT NULL,
B NUMBER
NULL,
C NUMBER
);
SQL> INSERT INTO ri_not_null VALUES (1,NULL, NULL);
SQL> INSERT INTO ri_not_null VALUES (2,3,4);
SQL> INSERT INTO ri_not_null VALUES (NULL,5,6);
The first to records can be inserted, the third cannot, throwing a ORA-01400: cannot insert NULL into
("RENE"."RI_NOT_NULL"."A").
The not null/null constraint can be altered with
SQL> ALTER TABLE ri_not_null MODIFY A NULL;
After this modification, the column a can contain null values.

1.5. Check
A check constraint allows to state a minimum requirement for the value in a column. If more complicated
requirements are desired, an insert trigger must be used.
The following table allows only numbers that are between 0 and 100 in the column a;
SQL> CREATE TABLE ri_check_1 (
A NUMBER CHECK (A BETWEEN 0 AND 100),
B NUMBER
);
Check constraints can be added after a table had been created:

Structure Query Language (SQL)- Integrity Constraints

Page 126 of 140


WK: 1 - Day: 1.1

SQL> ALTER TABLE ri_check_1


ADD CONSTRAINT ch_b CHECK (B > 50);
It is also possible to state a check constraint that check the value of more than one column. The following example
makes sure that the value of begin_ is smaller than the value of end_.
SQL> CREATE TABLE ri_check_2
BEGIN_
NUMBER,
END_
NUMBER,
VALUE_
NUMBER,
CHECK (BEGIN_ < END_)
);

2. Disabling Constraints
2.1. Disabling 'anonymous' constraint
SQL> CREATE TABLE foo(bar number,baz number,UNIQUE(bar,baz));
SQL> ALTER TABLE foo DISABLE UNIQUE (bar, baz);

2.2. Disabling named constraint


SQL> CREATE TABLE foo(bar number,baz number,constraint uq_foo UNIQUE(bar,baz));
SQL> ALTER TABLE foo DISABLE CONSTRAINT uq_foo;

Structure Query Language (SQL)- Indexes

Page 127 of 140


WK: 1 - Day: 1.1

Indexes
Indexes are totally optional structures that are intended to speed up the execution of SQL statements against table
data and cluster data. Indexes are used for direct access to a particular row or set of rows in a table. Indexes are
most typically organized as some type of tree structure.

1. Concepts and Facts


An index can be composed of a single column for a table, or it may be comprised of more than one column for a
table. An index based on more than one column is termed a concatenated (or composite) index.

Examples:
 The SSN key is used to track individual students at a university.
 The concatenated primary key index for an ENROLL table (SSN + SectionID + Term + Year) that is used to


track the enrollment of a student in a particular course section.


The maximum number of columns for a concatenated index is 32; but the combined size of the columns
cannot exceed about one-half of a data block size.

A unique index allows no two rows to have the same index entry. An example would be an index on student SSN.
A non-unique index allows more than one row to have the same index entry (this is also called a secondary key
index). An example would be an index on U.S. Mail zip codes.
A function-based index is created when using functions or expressions that involve one or more columns in the table
that is being indexed. A function-based index pre-computes the value of the function or expression and stores it in
the index. Function-based indexes can be created as either a B-tree or a bitmap index.
A partitioned index allows an index to be spread across several tablespaces - the index would have more than one
segment and typically access a table that is also partitioned to improve scalability of a system. This type of index
decreases contention for index lookup and increases manageability.
To create an index in our own schema:





The table to be indexed must be in our schema, OR


We have the INDEX privilege on the table to be indexed, OR
We have the CREATE ANY INDEX system privilege.

To create an index in another schema:




We have the CREATE ANY INDEX system privilege, AND


The owner of the other schema has a quota for the tablespace that will store the index segment (or
UNLIMITED TABLESPACE privilege).

2. Loading Data
Data initially loaded into a table will load more efficiently if the index is created after the table is created. This is
because the index must be updated after each row insertion if the index is created before loading data. Creating an
index on an existing table requires sort space typically memory values that are paged in and out of segments in the
TEMP tablespace allocated to a user. Users are also allocated memory for index creation based on the
SORT_AREA_SIZE parameter if memory is insufficient, then swapping takes place.

3. B-Tree Index Structure


The below figure illustrates in a very simple way the structure of a B-Tree index. A B-tree index usually stores a list of
primary key values and a list of associated ROWID values that point to the row location of the record with a given
primary key value. In this figure the ROWID values are represented by the pointers.

Structure Query Language (SQL)- Indexes

Page 128 of 140


WK: 1 - Day: 1.1

Figure 1-1. B-Tree Index

The top level of the index is called the Root. The Root points to entries at lower levels of the index - these lower
levels are termed Branch Blocks. A node in the index may store multiple (more than one) key values - in fact, almost
all B-Trees have nodes with multiple values - the tree structure grows upward and nodes split when they reach a
specified size. At the Leaf level the index entries point to rows in the table. At the Leaf level the index entries are
linked in a bi-directional chain that allows scanning rows in both ascending and descending order of key values - this
supports sequential processing as well as direct access processing. In a non-partitioned table, Key values are
repeated if multiple rows have the same key value this would be a non-unique index (unless the index is
compressed). Index entries are not made for rows that have all of the key columns NULL.
Leaf Index Format: The index entry at the Leaf level is made up of three components.





Entry Header - stores number of columns in the index and locking information about the row to which the
index points.
Key Column Length-Value Pairs - defines the size of the column in the key followed by the actual column
value. These pairs are repeated for each column in a composite index.
ROWID - This is the ROWID of a row in a table that contains the key value associated with this index entry.

Data Manipulation Language Effects: Any DML on a table also causes the Oracle Server to maintain the associated
indexes.






When a row is inserted into a table, the index must also be updated. This requires the physical insertion of
an index entry into the index tree structure.
When a row is deleted from a table, the index only has the entry "logically" deleted (turn a delete bit from off
to on). The space for the deleted row is not available for new entries until all rows in the block are deleted.
When a row key column is updated for a table, index has both logical deletion and physical insertion into the
index.
PCTFREE has no effect on an index except when the index is created. New entries to an index may be
added to an index block even if the free space in the block is less than the PCTFREE setting.
o If an indexed table has lots of rows to be inserted, set PCTFREE high to accommodate new index
values.
o If the table is static, set PCTFREE low.
o PCTUSED cannot be specified for indexes.

3.1. Creating B-Tree Indexes


An example CREATE INDEX command for a normal B-tree index is given here.
SQL> CREATE [UNIQUE] INDEX User350.Orders_Index ON User350.Orders(OrderId)
PCTFREE 20 INITTRANS 6 MAXTRANS 10
STORAGE (INITIAL 48K NEXT 48K PCTINCREASE 0 MAXEXTENTS 100)
LOGGING TABLESPACE Index01;

Structure Query Language (SQL)- Indexes

Page 129 of 140


WK: 1 - Day: 1.1

The UNIQUE clause specifies unique entries - the default is NONUNIQUE. Note that the owner's schema (User350)
is specified this is optional. The PCTFREE parameter is only effective when the index is created - after that, new
index block entries are made and PCTFREE is ignored. PCTFREE is ignored because entries are not updated instead a logical delete and physical insert of a new index entry is made. PCTUSED cannot be specified for an index
because updates are not made to index entries.
Use a low PCTFREE when the indexed column is system generated as would be the case with a sequence
(sequence indexes tend to increase in an ascending fashion) because new entries tend to be made to new data
blocks - there are no or few insertions into data blocks that already contain index entries. Use a high PCTFREE when
the indexed column or set of columns can take on random values that are not predictable. Such is the case when a
new Orderline row is inserted - the ProductID column may be a non-unique foreign key index and the product to be
sold on an Orderline is not predictable for any given order.
The Default and Minimum for INITTRANS is 2. The limit on MAXTRANS is 255 - this number would be inordinately
large. By default, LOGGING is on so that the index creation is logged into the redo log file. Specifying NOLOGGING
would increase the speed of index creation initially, but would not enable recovery at the time the index is created.
Interestingly, Oracle will use existing indexes to create new indexes whenever the key for the new index corresponds
to the leading part of the key of an existing index.

3.2. Indexes and Constraints


The UNIQUE and PRIMARY KEY constraints on tables are enforced by creating indexes on the unique key or
primary key creation of the index is automatic when such a constraint is enabled. We can specify a USING INDEX
clause to control the creation process. The index created takes the name of the constraint unless otherwise
specified.
Example: Creating a PRIMARY KEY constraint while creating a table.
SQL> CREATE TABLE District(
District_Number NUMBER(5) CONSTRAINT District_PK PRIMARY KEY,
District_Name VARCHAR2(50))
ENABLE PRIMARY KEY USING INDEX TABLESPACE Index01 PCTFREE 0;

4. Key-Compressed Index
This is a B-tree with compression compression eliminates duplicate occurrences of a key in an index leaf block.
SQL> CREATE INDEX Emp_Name ON Emp (Last_Name, First_Name)
TABLESPACE Index01 COMPRESS 1;
This approach breaks an index key into a prefix and suffix entry in the index block. Compression causes sharing of
the prefix entries among all suffix entries and save lots of space allowing the storage of more keys in a block.
Use key compression when:




The index is non-unique where the ROWID column is appended to the key to make the index key unique.
The index is a unique multicolumn index  example: Zip_Code + Last_Name.

5. Other General Topics


This section covers altering, rebuilding, coalescing, and dropping indexes. It also covers validating indexes and
identifying unused indexes. Guidelines are provided for when to index columns.

5.1. Altering Index Storage Parameters


The ALTER INDEX command is used to alter storage parameters. Use of the command is straight-forward as
illustrated in this example.
SQL> ALTER INDEX User350.Products_Region_Idx STORAGE(NEXT 200K MAXEXTENTS 200);
One of the most common changes is to increase MAXEXTENTS for an index as a system grows in size.
Allocating and De-allocating Index Space: If a DBA is going to insert a lot of rows into a table, performance can be
improved by adding extents to the indexes associated with the table prior to doing the inserts. This improves
performance by avoiding the dynamic addition of index extents. This can be accomplished by using the ALTER
INDEX command with the ALLOCATE EXTENT option.

Structure Query Language (SQL)- Indexes

Page 130 of 140


WK: 1 - Day: 1.1

SQL> ALTER INDEX User350.Products_Region_Idx


ALLOCATE EXTENT (SIZE 400K
DATAFILE '/a01/student/user350/oradata/user350index01.dbf');
We can DEALLOCATE unused index space after the insertions are complete. This will free up space that is not in
use within the tablespace.
SQL> ALTER INDEX User350.Products_Region_Idx DEALLOCATE UNUSED;

5.2. Creating an Index Online


Creating an Online Index allows Data Manipulation Language (DML) operations against the table while the index
build is being completed. DDL operations on the table are not allowed during the index creation process.
SQL> CREATE INDEX Manager_Employee_Idx ON Employee(Manager_ID, Emp_SSN) ONLINE;
There are some restrictions:






Temporary tables cannot be created/rebuilt online.


Partitioned indexes must be created/rebuilt one partition at a time.
We cannot de-allocate unused space during an online rebuild.
We cannot change the PCTFREE parameter for the whole index.

5.3. Rebuilding Indexes


We may improve system performance by rebuilding an index that is highly fragmented due to lots of physical
insertions and logical deletions. Such may be the case for a SALES_ORDER table where filled orders are deleted
over time.
SQL> ALTER INDEX User350.Products_Region_Idx REBUILD TABLESPACE Index01;
If we rebuild an index from an existing index, the rebuild operation is more efficient because the index information
does not need to be sorted - it is already sorted. We can specify a new tablespace if necessary for the rebuilt index.
The older index is deleted after the new index is rebuilt. We must have sufficient space in the tablespace for the
old/new index during the rebuild operation.
Queries use the old index while the rebuild operation is under way.

We can also specify the ONLINE option when rebuilding an index.


SQL> ALTER INDEX User350.Products_Region_Idx REBUILD ONLINE;

5.4. Coalescing Indexes


This is an alternative to the ALTER INDEXREBUILD command it eliminates index fragmentation. Coalesce on
an index is a block rebuild that is done online. In situations where a B-tree index has leaf blocks that can be freed up
for reuse, we can merge leaf blocks using the ALTER INDEXCOALESCE statement.
SQL> ALTER INDEX User350.Products_Region_Idx COALESCE;
In this figure, the first two leaf node blocks are about 50% full fragmentation is evident. After coalescing, blocks are
merged freeing up a block for reuse.

Figure 3-1. Coalescing Index

Structure Query Language (SQL)- Indexes

Page 131 of 140


WK: 1 - Day: 1.1

5.4.1. When to Rebuild or Coalesce


Rebuild Index

Coalesce Index

To quickly move an index to another tablespace.

Cannot move the index to another tablespace.

Requires more disk space.

Operation does not require more disk space.

Creates new index tree height of tree may shrink.

Only coalesces leaf blocks.

Enables changing storage and tablespace parameters.

Frees up index leaf blocks for use.

5.5. Checking Index Validity


The ANALYZE INDEX command with the VALIDATE STRUCTURE option can be used to check for block corruption
in an index.
SQL> ANALYZE INDEX dbock.pk_course VALIDATE STRUCTURE;
We can query the INDEX_STATS view and obtain information about the index.
SQL> ANALYZE INDEX Course_PK VALIDATE STRUCTURE;
Index analyzed.
SQL> SELECT blocks, pct_used, distinct_keys, lf_rows, del_lf_rows
FROM index_stats;
BLOCKS
PCT_USED DISTINCT_KEYS
LF_ROWS DEL_LF_ROWS
---------- ---------- ------------- ---------- ----------15
1
2
2
0
An index needs to be reorganized when the proportion of deleted rows (DEL_LF_ROWS) to existing rows
(LF_ROWS short for Leaf) is greater than 30%.

5.6. Dropping an Index


DBAs drop indexes if they are no longer needed by an application, i.e., the application is discontinued. We also drop
indexes prior to large data loads - this improves performance and tends to use index space more efficiently. We can
also drop indexes that are marked by the system as INVALID because of some type of instance failure, or if the index
is corrupt.
SQL> DROP INDEX index_name;
We cannot drop an index used to implement an integrity constraint. We would first need to remove the integrity
constraint by altering the table, and then drop the index.

5.7. Identifying Unused Indexes








Beginning with Oracle9i, statistics about the usage of an index can be gathered and displayed in
V$OBJECT_USAGE.
Start usage monitoring of an index:
SQL> ALTER INDEX user350.dept_id_idx MONITORING USAGE;
Stop usage monitoring of an index:
SQL> ALTER INDEX user350.dept_id_idx NOMONITORING USAGE;
If the information gathered indicates that an index is never used, the index can be dropped.
In addition, eliminating unused indexes cuts down on overhead that the Oracle server has to do for DML,
thus performance is improved.

Each time the MONITORING USAGE clause is specified, V$OBJECT_USAGE will be reset for the specified index.
The previous information is cleared or reset, and a new start time is recorded.

5.8. Guidelines for Creating Indexes


A table can have any number of indexes, but the more indexes, the more overhead that is associated with DML
operations:

Structure Query Language (SQL)- Indexes




Page 132 of 140


WK: 1 - Day: 1.1

A single row insertion or deletion requires updating all indexes on the table.
An update operation may or may not affect indexes depending on the column updated.

The use of indexes involves a tradeoff - query performance tends to speed up, but data manipulation language
operations tend to slow down.





Query performance improves because the index speeds up row retrieval.


DML operations slow down because along with row insertions, deletions, and updates, the indexes
associated with a table must also have insertions and deletions completed.
For very volatile tables, minimize the number of indexes used.

When possible, store indexes to a tablespace that does not have rollback segments, temporary segments, and
user/data tables DBAs usually create a separate tablespace just used for index segments.
We can minimize fragmentation by using extent sizes that are at least multiples of 5 times the DB_BLOCK_SIZE for
the database. Create an index when row retrieval involves less than 15% of a large table's rows retrieval of more
rows is generally more efficient with a full table scan. We may want to use NOLOGGING when creating large indexes
- we can improve performance by avoiding redo generation.

 Indexes created with NOLOGGING requires a backup as their creation is not archived.
Example:
SQL> CREATE BITMAP INDEX User350.Products_Region_Idx
ON User350.Products_Region (RegionId ASC) NOLOGGING;
Usually index entries are smaller than the rows they index. Data blocks that store index entries tend to store more
entries in each block, so the INITRANS parameter should be higher on indexes than on their related tables.

Columns that are strong candidates for indexing include:


 Take into consideration the typical queries that will access the table. A concatenated index is only used by







Oracle in retrieving data when the leading column of the index is used in a query's WHERE clause.
o The order of the columns in the CREATE INDEX statement affect query performance specify the
most frequently used columns first.
o An index on column1, column2, and column3 can improve performance for queries with WHERE
clauses on column1 or on column1+column2, but will not be used for queries with a WHERE clause
that just uses column2 or column3.
Columns used in join operations join operations perform better if the columns used in the join are indexed.
Columns where the values stored in the columns are relatively unique (but not number columns that store
currency values).
Columns with a wide range of values (use regular B-tree indexes).
Columns with a small range of values (use bitmap indexes).
Columns with few NULL values and queries often search for rows having some value.

Small tables don't need indexes but it is a good idea to still index the Primary Key.

Structure Query Language (SQL)- Sequences

Page 133 of 140


WK: 1 - Day: 1.1

Sequences in Oracle
Introduction
Use the CREATE SEQUENCE statement to create a sequence, which is a database object from which multiple users
may generate unique integers. You can use sequences to automatically generate primary key values.
When a sequence number is generated, the sequence is incremented, independent of the transaction committing or
rolling back. If two users concurrently increment the same sequence, then the sequence numbers each user acquires
may have gaps, because sequence numbers are being generated by the other user. One user can never acquire the
sequence number generated by another user. After a sequence value is generated by one user, that user can
continue to access that value regardless of whether the sequence is incremented by another user.
Sequence numbers are generated independently of tables, so the same sequence can be used for one or for multiple
tables. It is possible that individual sequence numbers will appear to be skipped, because they were generated and
used in a transaction that ultimately rolled back. Additionally, a single user may not realize that other users are
drawing from the same sequence.
After a sequence is created, you can access its values in SQL statements with the CURRVAL pseudocolumn, which
returns the current value of the sequence, or the NEXTVAL pseudocolumn, which increments the sequence and
returns the new value.
A sequence is a highly scalable, non-blocking, generator that generates unique numbers.
This is demonstrated in the following example. First, two tables are created:
SQL> CREATE TABLE SEQ_EX_A (
N NUMBER
);
SQL> CREATE TABLE SEQ_EX_B (
S NUMBER,
N NUMBER
);
One table is populated with five rows:
SQL>
SQL>
SQL>
SQL>
SQL>

INSERT
INSERT
INSERT
INSERT
INSERT

INTO
INTO
INTO
INTO
INTO

SEQ_EX_A
SEQ_EX_A
SEQ_EX_A
SEQ_EX_A
SEQ_EX_A

VALUES
VALUES
VALUES
VALUES
VALUES

(55);
( 3);
(27);
(81);
(32);

A sequence is generated:
SQL> CREATE SEQUENCE SEQ_A START WITH 1 INCREMENT BY 1;
Then, the values of table SEQ_EX_A are filled into SEQ_EX_B. The sequence generates a (as mentioned: unique)
number by calling NEXTVAL on it:
SQL> INSERT INTO SEQ_EX_B SELECT SEQ_A.NEXTVAL, N FROM SEQ_EX_A;
The table's content:
SQL> SELECT * FROM SEQ_EX_B;
This returns:
S
N
---------- ---------1
55
2
3
3
27
4
81
5
32

Structure Query Language (SQL)- Views

Page 134 of 140


WK: 1 - Day: 1.1

Views
Definition







A VIEW is a virtual table that does not exist in reality, but is a logical definition of a set of related columns,
usually from multiple tables.
A VIEW presents data to the end user of an application system the way that the end user is used to seeing
the data.
o
For example, the Customer Order Form is a view of data from several different tables including
CUSTOMER, ORDERS, PRODUCT, ORDERLINE, and SALESPERSON.
A VIEW can also be used to simplify query generation and to add data security to a database by limiting the
data that an end user can access.
A VIEW definition is permanently stored as part of the database.
The example below creates a view named PATIENT_BILL that includes the PATIENT_NO, ITEM_CODE and
CHARGE columns from the BILLED table and the DESCRIPTION column from the ITEM table, and the
DATE_DISCHARGED from the PATIENT table.

Create a View
SQL> CREATE VIEW patient_bill AS
SELECT B.patient_no, P.pat_name,
B.item_code, charge,
description, date_discharged
FROM patient P, billed B, item I
WHERE P.patient_no = B.patient_no AND
I.item_code = B.item_code;





View created.
Note that the relationship from PATIENT to BILLED is 1:N and the relationship from ITEM to BILLED is 1:N.
In other words, the BILLED table is the intersection table linking PATIENT and ITEM.
Now we can query the view PATIENT_BILL just as we would a table. When we execute the query, the view
is generated by the DBMS and loaded with data, and then our query is executed.
SQL> SELECT patient_no, item_code, charge,
description
FROM patient_bill
WHERE patient_no = 1117;
PATIENT_NO ITEM_CODE
CHARGE DESCRIPTION
---------- --------- -------- --------------------1117
2222
7.54 Syringe, 19 gauge
1117
2255
25 Saline Soln, 1 liter
1117
2245
167.67 Surgical Prep Pack #8
1117
2224
222.21 Surgical Prep Pack #4
1117
2267
4.92 Bed Pan

Derived Columns






A view may contain derived (or virtual) columns.


For example, the total charges by patient for room and special items in a room (item codes between 2200
and 2250).
A view for this aggregate data can be created from the PATIENT_BILL view that was created in the example
above.
The new view (code shown below for this view of a view) named ROOM_CHARGE has two virtual columns
named OCCUPANT and ROOM_CHGS.
Note that ROOM_CHARGES is the sum of the charges for an occupant of the room.
SQL> CREATE VIEW room_charge (occupant, room_chgs) AS
SELECT pat_name, sum(CHARGE)
FROM patient_bill

Structure Query Language (SQL)- Views

WHERE item_code BETWEEN 2200 AND 2250


GROUP BY pat_name;

Selecting from a View




Now we can select charges for an occupant with the simple query given below.
SQL> SELECT occupant, room_chgs
FROM room_charge
WHERE room_chgs > 100;
OCCUPANT
ROOM_CHGS
-------------------- ---------Barbara Streisand
175
Eminem
782.55
Sally Field
397.42

Which is equivalent to:


SQL> SELECT pat_name, SUM(charge)
FROM patient_bill
WHERE item_code BETWEEN 2200 AND 2250
GROUP BY pat_name
HAVING SUM(charge) > 100;
PAT_NAME
SUM(charge)
-------------------- ----------Barbara Streisand
175
Eminem
782.55
Sally Field
397.42

Page 135 of 140


WK: 1 - Day: 1.1

Structure Query Language (SQL)- SET Commands

Page 136 of 140


WK: 1 - Day: 1.1

SET Commands
Sets a system variable to alter the SQL*Plus environment settings for our current session, for example:






Display width for data


Turn on HTML formatting
Enabling or disabling printing of column headings
Number of lines per page

In iSQL*Plus, we can also use the System Variables screen to set system variables. SET system_variable value
where system_variable and value represent one of the following clauses:
Syntax:
SQL> SET option value
SQL> SHO[W] option
Options: most of these have an abbreviated and a long form e.g. APPINFO or APPI will do the same thing we can get
a list of the set options in SQLPLUS with the command
SQL> HELP SET
APPI[NFO]{ON|OFF|text}

Application info for performance monitor (see DBMS_APPLICATION_INFO)

ARRAY[SIZE] {15|n}

Fetch size (1 to 5000) the number of rows that will be retrieved in one go.

AUTO[COMMIT]
{OFF|ON|IMM[EDIATE]|n}
AUTOP[RINT] {OFF|ON}

Autocommit commits after each SQL command or PL/SQL block

AUTORECOVERY [ON|OFF]

Configure the RECOVER command to automatically apply archived redo log


files during recovery - without any user confirmation.

AUTOT[RACE]
{OFF|ON|TRACE[ONLY]}
[EXP[LAIN]] [STAT[ISTICS]]

Display a trace report for SELECT, INSERT, UPDATE or DELETE


statements EXPLAIN shows the query execution path by performing an
EXPLAIN PLAN.
STATISTICS displays SQL statement statistics. Using ON or TRACEONLY
with no explicit options defaults to EXPLAIN STATISTICS

BLO[CKTERMINATOR]
{.|c|OFF|ON}
CMDS[EP] {;|c|OFF|ON}

Set the non-alphanumeric character used to end PL/SQL blocks to c

COLSEP { |text}

The text to be printed between SELECTed columns normally a space.

COM[PATIBILITY]
{V5|V6|V7|V8|NATIVE}

Version of oracle - see also init.ora COMPATIBILITY=


We can set this back by up to 2 major versions e.g. Ora 9 supports 8 and 7

CON[CAT] {.|c|OFF|ON}

Termination character for substitution variable reference default is a period.

COPYC[OMMIT] {0|n}

The COPY command will fetch n batches of data between commits.


(n= 0 to 5000) the size of each fetch=ARRAYSIZE.
If COPYCOMMIT = 0, COPY will commit just once - at the end.

COPYTYPECHECK {OFF|ON}

Suppress the comparison of data types while inserting or appending to DB2

DEF[INE] {&|c|OFF|ON}

c = the char used to prefix substitution variables.


ON or OFF controls whether to replace substitution variables with their
values.
(this overrides SET SCAN)

DESCRIBE [DEPTH
{1|n|ALL}][LINENUM
{ON|OFF}][INDENT {ON|OFF}]
ECHO {OFF|ON}

Sets the depth of the level to which we can recursively describe an object (1
to 50) see the DESCRIBE command

Automatic PRINTing of bind variables.

Change or enable command separator - default is a semicolon (;)

Display commands as they are executed

Structure Query Language (SQL)- SET Commands

EMB[EDDED] {OFF|ON}

OFF = report printing will start at the top of a new page.


ON = report printing may begin anywhere on a page.

ESC[APE] {\|c|OFF|ON}

Defines the escape character. OFF undefines. ON enables.

FEED[BACK] {6|n|OFF|ON}

Display the number of records returned (when rows > n )


OFF (or n=0) turns the display off
ON sets n=1

Page 137 of 140


WK: 1 - Day: 1.1

FLAGGER
Checks to make sure that SQL statements conform to the ANSI/ISO SQL92
{OFF|ENTRY|INTERMED[IATE]|FU standard. non-standard constructs are flagged as errors and displayed
LL}
FLU[SH] {OFF|ON}
Buffer display output (OS)
(no longer used in Oracle 9)
HEA[DING] {OFF|ON}

print column headings

HEADS[EP] {||c|OFF|ON}

Define the heading separator character (used to divide a column heading


onto > one line.)
OFF will actually print the heading separator char

INSTANCE
[instance_path|LOCAL]

Change the default instance for our session, this command may only be
issued when not already connected and requires Net8

LIN[ESIZE] {150|n}

Width of a line (before wrapping to the next line)


Earlier versions default to 80, Oracle 9 is 150

LOBOF[FSET] {n|1}

Starting position from which CLOB and NCLOB data is retrieved and
displayed

LOGSOURCE [pathname]

Change the location from which archive logs are retrieved during recovery
normally taken from LOG_ARCHIVE_DEST

LONG {80|n}

Set the maximum width (in chars) for displaying and copying LONG values.

LONGC[HUNKSIZE] {80|n}

Set the fetch size (in chars) for retrieving LONG values.

MARK[UP] HTML [ON|OFF]


Output HTML text, which is the output used by iSQL*Plus.
[HEAD text] [BODY text]
[TABLE text]
[ENTMAP {ON|OFF}][SPOOL
{ON|OFF}]
[PRE[FORMAT]
{ON|OFF}]
NEWP[AGE] {1|n} NULL text
The number of blank lines between the top of each page and the top title.
0 = a formfeed between pages.
NULL text

Replace a null value with 'text'


The NULL clause of the COLUMN command will override this for a given
column.

NUMF[ORMAT] format

The default number format.

NUM[WIDTH] {10|n}

The default width for displaying numbers.

PAGES[IZE] {14|n}

The height of the page - number of lines.


0 will suppress all headings, page breaks, titles

PAU[SE] {OFF|ON|text}

press [Return] after each page


enclose text in single quotes

RECSEP
{WR[APPED]|EA[CH]|OFF}

Print a single line of the RECSEPCHAR between each record.


WRAPPED = print only for wrapped lines
EACH=print for every row

Structure Query Language (SQL)- SET Commands

Page 138 of 140


WK: 1 - Day: 1.1

RECSEPCHAR {_|c}

Define the RECSEPCHAR character, default= ' '

SCAN {OFF|ON}

OFF = disable substitution variables and parameters

SERVEROUT[PUT] {OFF|ON}
[SIZE n] [FOR[MAT]
{WRA[PPED]|WOR[D_WRAPPED]|TR
U[NCATED]}]
SHOW[MODE] {OFF|ON}

whether to display the output of stored procedures (or PL/SQL blocks) i.e.,
DBMS_OUTPUT.PUT_LINE
SIZE = buffer size (2000-1,000,000) bytes

SPA[CE] {1|n}

The number of spaces between columns in output (1-10)

SQLBL[ANKLINES] {ON|OFF}

Allow blank lines within an SQL command. Reverts to OFF after the current
command/block.

SQLC[ASE]
{MIX[ED]|LO[WER]|UP[PER]}

Convert the case of SQL commands and PL/SQL blocks


(but not the SQL buffer itself)

SQLPLUSCOMPAT[IBILITY]
{x.y[.z]}

Set the behavior or output format of VARIABLE to that of the release or


version specified by x.y[.z].

SQLCO[NTINUE] {> |text}

Continuation prompt (used when a command is continued on an additional


line using a hyphen -)

SQLN[UMBER] {OFF|ON}

Set the prompt for the second and subsequent lines of a command or
PL/SQL block.
ON = set the SQL prompt = the line number.
OFF = set the SQL prompt = SQLPROMPT.

SQLPRE[FIX] {#|c}

set a non-alphanumeric prefix char for immediately executing one line of SQL
(#)

SQLP[ROMPT] {SQL>|text}

Set the command prompt.

SQLT[ERMINATOR]
{;|c|OFF|ON}|

Set the char used to end and execute SQL commands to c.


OFF disables the command terminator - use an empty line instead.
ON resets the terminator to the default semicolon (;).

SUF[FIX] {SQL|text}

Default file extension for SQL scripts

TAB {OFF|ON}

Format white space in terminal output.


OFF = use spaces to format white space.
ON = use the TAB char.
Note this does not apply to spooled output files.
The default is system-dependent. Enter SHOW TAB to see the default value.

TERM[OUT] {OFF|ON}

OFF suppresses the display of output from a command file


ON displays the output.

Display old and new settings of a system variable

TERMOUT OFF does not affect the output from commands entered
interactively.
TI[ME] {OFF|ON}

Display the time at the command prompt.

TIMI[NG] {OFF|ON}

ON = display timing statistics for each SQL command or PL/SQL block run.
OFF = suppress timing statistics

TRIM[OUT] {OFF|ON}

Display trailing blanks at the end of each line.


ON = remove blanks, improving performance
OFF = display blanks.
This does not affect spooled output.
SQL*Plus ignores TRIMOUT ON unless we set TAB ON.

TRIMS[POOL] {ON|OFF}

Allows trailing blanks at the end of each spooled line.

Structure Query Language (SQL)- SET Commands

Page 139 of 140


WK: 1 - Day: 1.1

This does not affect terminal output.


UND[ERLINE] {-|c|ON|OFF}

Set the char used to underline column headings to c.

VER[IFY] {OFF|ON}

ON = list the text of a command before and after replacing substitution


variables with values.
OFF = dont display the command.

WRA[P] {OFF|ON}

Controls whether to truncate or wrap the display of long lines.


OFF = truncate
ON = wrap to the next line
The COLUMN command (WRAPPED and TRUNCATED clause) can
override this for specific columns.

Structure Query Language (SQL)- Product List

Page 140 of 140


WK: 1 - Day: 1.1

Oracle Products List


1. Database










Database 10g Enterprise/Standard Editions


Database 10g Express Edition
Cluster File System
Cluster Verification Utility
Instant Client
Rdb Products
Secure Backup
SQL Developer
Workflow Server

1.1. Embedded




TimesTen In-Memory Database


Berkeley DB
Database Lite

2. Search


Secure Enterprise Search

3. Enterprise Management



Enterprise Manager 10g Grid Control


Enterprise Manager Grid Control Plugins

4. Tape Backup


Secure Backup

5. Migration Tools






Database Migration Verifier


Oracle-on-Linux VMware Tool Kits
JDeveloper App Migration Assistant
Migration Tool Kits
Migration Workbench

6. Archived Products









Oracle9i Database
Oracle9i Lite
Oracle9i Personal
Oracle9i Internet Directory
Oracle9i Unified Messaging
Oracle9iAS Wireless
Discoverer Desktop
Software Configuration Manager

7. Middleware


















Application Server 10g


Application Server MapViewer
Application Server Adapters
Application Server Containers for J2EE
Application Server Integration
Application Server Personalization
Application Server Web Cache
Business Intelligence Standard Edition
Collaboration Suite 10g
Content Management SDK
Content Services
Forms & Reports Services
HTTP Server
Identity Management
Portal
Real-Time Collaboration
Sensor Edge Server

7.1. Developer Tools






















ADF Faces
BPEL Process Manager
Business Intelligence Beans
BI Spreadsheet Add-in
Data Miner
Designer
Developer Suite 10g
Developer Tools for VS .NET
Forms & Reports Developer
JDeveloper & ADF
Portal Developer Kit
SQL Developer
Service Registry
SOA Suite
TopLink
Warehouse Builder
XML Developer's Kit
XML Publisher
Zend Core for Oracle