Chapter 9: Retrieving, Restricting, and Sorting Data Using SQL377 \o region_id o street_address o state_province \o country_id \o manager_id \o location_id \o manager_id \o department_id
Trang 1many employees may have one manager, but the manager is also an employee The relationship is implemented by the column manager_id being a foreign key to
employee_id, which is the table’s primary key
The second relationship that may require explanation is between DEPARTMENTS and EMPLOYEES, which is bidirectional The one department–to–many employees relationship simply states that there may be many staff members in each department, based on the EMPLOYEES department_id column being a foreign key to the
DEPARTMENTS primary key department_id column The one employee–to–many departments relationship shows that one employee could be the manager of several departments and is implemented by the manager_id column in DEPARTMENTS being
a foreign key to the primary key employee_id column in EMPLOYEES
Table 9-1 shows the columns of each table in the HR schema, using the notation described in the earlier section “Data Normalization” to indicate primary keys (#), foreign keys (\), and whether columns are optional (o) or mandatory (*)
The tables are as follows:
• REGIONS has rows for major geographical areas
• COUNTRIES has rows for each country, which are optionally assigned to a region
• LOCATIONS includes individual addresses, which are optionally assigned to
a country
• DEPARTMENTS has a row for each department, optionally assigned to a location and optionally with a manager (who must exist as an employee)
• EMPLOYEES has a row for every employee, each of whom must be assigned to
a job and optionally to a department and to a manager The managers must themselves be employees
• JOBS lists all possible jobs in the organization It is possible for many
employees to have the same job
• JOB_HISTORY lists previous jobs held by employees, uniquely identified by employee_id and start_date; it is not possible for an employee to hold two jobs concurrently Each job history record will refer to one employee, who will have had one job at that time and may have been a member of one department This HR schema is used for many of the exercises and examples embedded in the chapters of this book and does need to be available
The WEBSTORE schema might already have been created if you worked through this book from Chapter 1 In this chapter, the entities and their relationships will be defined and we will create the schema and the necessary objects The WEBSTORE schema consists of four tables, linked by primary key to foreign key relationships Figure 9-4 illustrates the relationships between the tables, as an entity-relationship diagram
Trang 2Chapter 9: Retrieving, Restricting, and Sorting Data Using SQL
377
\o region_id
o street_address
o state_province
\o country_id
\o manager_id
\o location_id
\o manager_id
\o department_id
#* start_date
\o department_id
Table 9-1
The Tables and
Columns on the
HR Schema
Trang 3The store maintains product, customer, and order details in the appropriately named tables Each order may consist of multiple products with various quantities, and these records are stored in the ORDER_ITEMS table Each table has a primary key except for the ORDER_ITEMS table The order_item_id column stores line item numbers for each distinct product that is part of the order, but each order is associated with one or more records from the ORDER_ITEMS table
The tables are as follows:
• PRODUCTS has rows for each item, including description, status, price, and stock information ORDER_ITEMS may be associated with only one product
A foreign key relationship exists between these tables, ensuring that only valid products can appear in records in the ORDER_ITEMS table
• CUSTOMERS stores information for each customer
Figure 9-4 The WEBSTORE entity-relationship diagram
Trang 4Chapter 9: Retrieving, Restricting, and Sorting Data Using SQL
379
• ORDERS stores customer order information One customer may be associated
with many orders A foreign key constraint governs this relationship, ensuring
that orders cannot be placed by nonexistent customers
• ORDER_ITEMS stores the detail line items associated with each order
Demonstration Schema Creation
If the database you are using was created specifically for studying for the OCP SQL
examination, the demonstration schemas should have been created already They are an
option presented by the Database Configuration Assistant when it creates a database
If the schemas were not created at database creation time, they can be created by
running scripts installed into the Oracle Home of the database These scripts will need
to be run from SQL*Plus or SQL Developer as a user with SYSDBA privileges The script
will prompt for certain values as it runs For example, on Linux, first launch SQL*Plus
from an operating system prompt:
sqlplus / as sysdba
There are various options for this connection, but the preceding syntax will usually
work if the database is running on the same machine where you are running SQL*Plus
Then invoke the script from the SQL> prompt:
SQL> @?/demo/schema/human_resources/hr_main.sql
The “?” character is a variable that SQL*Plus will expand into the path to the
Oracle Home directory The script will prompt for HR’s password, default tablespace,
and temporary tablespace; the SYS password; and a destination for the logfile of the
script’s running Typical values for the default tablespace and temporary tablespace are
USERS and TEMP, but these will have to have been created already After completion,
you will be connected to the database as the new HR user To verify this, run this
statement:
SQL> show user;
You will see that you are currently connected as HR; then run
SQL> select table_name from user_tables;
You will see a list of the seven tables in the HR schema
To create the WEBSTORE schema (if it does not already exist), run the following
statements to create the necessary objects and insert a dataset that will be used in later
exercises and examples:
sqlplus / as sysdba
create user webstore identified by admin123
default tablespace users temporary tablespace temp quota unlimited on users;
grant create session, create table, create sequence to webstore;
Trang 5create table customers(
customer_id number(8) not null constraint pk_customer_id primary key,
join_date date default sysdate not null,
customer_status varchar2(8) not null, customer_name varchar2(20) not null,
creditrating varchar2(10) not null, email varchar2(50) not null);
create table products(
product_id number(8) not null constraint pk_product_id primary key,
product_description varchar2(20) not null,
product_status varchar2(8) not null, price number(10,2) not null,
price_date date not null, stock_count number(8) not null);
create table orders(
order_id number(8) not null constraint pk_order_id primary key,
order_date date not null, order_status varchar2(8) not null,
order_amount number(10,2) not null,
customer_id number(8) constraint fk_customer_id references customers (customer_id));
create table order_items(
order_item_id number(8) not null,
order_id number(8) constraint fk_order_id references orders(order_id),
product_id number(8) constraint fk_prod_id references products(product_id),
quantity number);
create sequence cust_seq;
create sequence order_seq;
create sequence prod_seq;
Once these schema objects are created, use the following INSERT statements that make use of substitution variables to populate (or seed) the tables with several rows
of data based on the sample data in Table 9-2
insert into customers
(customer_id, customer_status, customer_name, creditrating, email) values (cust_seq.nextval, '&cust_status', '&cust_name', '&creditrating', '&email');
insert into products(product_id, product_description,
product_status, price, price_date, stock_count)
values (prod_seq.nextval, '&product_description',
'&product_status', &price, sysdate, &stock_count);
insert into orders(order_id, order_date, order_status,
order_amount, customer_id)
values (order_seq.nextval, sysdate, '&order_status',
&order_amount, &customer_id);
insert into order_items values (&item_id, &order_id, &product_id, &quantity);
Trang 6Chapter 9: Retrieving, Restricting, and Sorting Data Using SQL
381
Execute a Basic SELECT Statement
The practical capabilities of the SELECT statement are realized in its execution The
key to executing any query language statement is a thorough understanding of its
syntax and the rules governing its usage You will learn more about this topic first, then
about the execution of a basic query, and finally about expressions and operators,
which exponentially increase the utility of data stored in relational tables Next, the
concept of a null value is demystified, as its pitfalls are exposed These topics are
covered in the following four sections:
• Syntax of the primitive SELECT statement
• Rules are meant to be followed
• SQL expressions and operators
• NULL is nothing
Customer Status Customer Name Credit Rating Email
Product Description Product Status Price Stock Count
Order Status Order Amount Customer Id
Order Item Id Order Id Product Id Quantity
Table 9-2 Sample Data for the WEBSTORE Schema
Trang 7Syntax of the Primitive SELECT Statement
In its most primitive form, the SELECT statement supports the projection of columns and the creation of arithmetic, character, and date expressions It also facilitates the elimination
of duplicate values from the results set The basic SELECT statement syntax is as follows:
SELECT *|{[DISTINCT] column|expression [alias], }
FROM table;
The special keywords or reserved words of the SELECT statement syntax appear in uppercase When using the commands, however, the case of the reserved words in your query statement does not matter Reserved words cannot be used as column names or other database object names SELECT, DISTINCT, and FROM are three keywords A SELECT statement always contains two or more clauses The two mandatory clauses are the SELECT clause and the FROM clause The pipe symbol (|) is used to denote OR So you can read the first form of the preceding SELECT statement as
SELECT *
FROM table;
In this format, the asterisk symbol (*) is used to denote all columns SELECT *
is a succinct way of asking Oracle to return all possible columns It is used as a
shorthand, time-saving symbol instead of typing in SELECT column1, column2, column3, column4,…,columnX, to select all the columns The FROM clause specifies
which table to query to fetch the columns requested in the SELECT clause
You can issue the following SQL command to retrieve all the columns and all the rows from the REGIONS table in the HR schema:
select * from regions;
When this command is executed, it returns all the rows of data and all the columns belonging to this table Use of the asterisk in a SELECT statement is sometimes referred
to as a “blind” query because the exact columns to be fetched are not specified
The second form of the basic SELECT statement has the same FROM clause as the first form, but the SELECT clause is different:
SELECT {[DISTINCT] column|expression [alias],…}FROM table;
This SELECT clause can be simplified into two formats:
SELECT column1 (possibly other columns or expressions) [alias optional]
OR
SELECT DISTINCT column1 (possibly other columns or expressions) [alias
op-tional]
An alias is an alternative name for referencing a column or expression Aliases
are typically used for displaying output in a user-friendly manner They also serve as shorthand when referring to columns or expressions to reduce typing Aliases will be discussed in detail later in this chapter By explicitly listing only the relevant columns in the
SELECT clause you, in effect, project the exact subset of the results you wish to retrieve The
following statement will return just the REGION_NAME column of the REGIONS table:
Trang 8Chapter 9: Retrieving, Restricting, and Sorting Data Using SQL
383
You may be asked to obtain all the job roles in the organization that employees have
historically fulfilled For this you can issue the command: SELECT * FROM JOB_
HISTORY However, in addition, the SELECT * construct returns the EMPLOYEE_ID,
START_DATE, and END_DATE columns The uncluttered results set containing only
the JOB_ID and DEPARTMENT_ID columns can be obtained with the following
statement:
select job_id,department_id from job_history;
Using the DISTINCT keyword allows duplicate rows to be eliminated from the
results set In numerous situations a unique set of rows is required It is important to
note that the criterion employed by the Oracle server in determining whether a row is
unique or distinct depends entirely on what is specified after the DISTINCT keyword
in the SELECT clause Selecting distinct JOB_ID values from the JOB_HISTORY table
with the following query will return the eight distinct job types
select distinct job_id from job_history;
An important feature of the DISTINCT keyword is the elimination of duplicate
values from combinations of columns.
Rules Are Meant to Be Followed
SQL is a fairly strict language in terms of syntax rules, but it remains simple and
flexible enough to support a variety of programming styles This section discusses
some of the basic rules governing SQL statements
Uppercase or Lowercase
It is a matter of personal taste about the case in which SQL statements are submitted
to the database Many developers, including the authors of this book, prefer to write
their SQL statements in lowercase There is also a common misconception that SQL
reserved words need to be specified in uppercase Again, this is up to you Adhering
to a consistent and standardized format is advised
There is one caveat regarding case sensitivity When interacting with literal values,
case does matter Consider the JOB_ID column from the JOB_HISTORY table This
column contains rows of data that happen to be stored in the database in uppercase;
for example, SA_REP and ST_CLERK When requesting that the results set be restricted
by a literal column, the case is critical The Oracle server treats the request for the rows
in the JOB_HISTORY table that contain a value of St_Clerk in the JOB_ID column
differently from the request for rows that have a value of ST_CLERK in JOB_ID column
Metadata about different database objects is stored by default in uppercase in the
data dictionary If you query a database dictionary table to return a list of tables owned
by the HR schema, it is likely that the table names returned will be stored in uppercase
This does not mean that a table cannot be created with a lowercase name; it can be It
is just more common and the default behavior of the Oracle server to create and store
tables, columns, and other database object metadata in uppercase in the database
dictionary
Trang 9EXAM TIP SQL statements may be submitted to the database in any case
You must pay careful attention to case when interacting with character literal data and aliases Requesting a column called JOB_ID or job_id returns the same column, but asking for rows where the JOB_ID value is PRESIDENT
is different from asking for rows where the value is President
Statement Terminators
Semicolons are generally used as SQL statement terminators SQL*Plus always
requires a statement terminator, and usually a semicolon is used A single SQL
statement or even groups of associated statements are often saved as script files for future use Individual statements in SQL scripts are commonly terminated by a line break (or carriage return) and a forward slash on the next line, instead of a semicolon You can create a SELECT statement, terminate it with a line break, include a forward slash to execute the statement, and save it in a script file The script file can then be called from within SQL*Plus Note that SQL Developer does not require a statement terminator if only a single statement is present, but it will not object if one is used It
is good practice to always terminate your SQL statements with a semicolon Several examples of SQL*Plus statements follow:
select country_name, country_id, location_id from countries;
select city, location_id,
state_province, country_id
from locations
/
The first example demonstrates two important rules First, the statement is terminated
by a semicolon Second, the entire statement is written on one line It is entirely acceptable for a SQL statement either to be written on one line or to span multiple lines as long as no words in the statement span multiple lines The second sample of code demonstrates a statement that spans three lines that is terminated by a new line and executed with a forward slash
Indentation, Readability, and Good Practice
Consider the following query:
select city, location_id,
state_province, country_id
from locations
/
This example highlights the benefits of indenting your SQL statement to enhance the readability of your code The Oracle server does not object if the entire statement is written on one line without indentation It is good practice to separate different clauses of the SELECT statement onto different lines When an expression in a clause
is particularly complex, it often enhances readability to separate that term of the statement onto a new line When developing SQL to meet your reporting needs, the process is often iterative The SQL interpreter is far more useful during development if
Trang 10Chapter 9: Retrieving, Restricting, and Sorting Data Using SQL
385
complex expressions are isolated on separate lines, since errors are usually thrown in
the format of: “ERROR at line X:” This makes the debugging process much simpler
Exercise 9-1: Answer Your First Questions with SQL In this step-by-step
exercise, you make a connection using SQL*Plus as the HR user to answer two questions
using the SELECT statement
Question 1: How many unique departments have employees currently working in
them?
1 Start SQL*Plus and connect to the HR schema
2 You may initially be tempted to find the answer in the DEPARTMENTS table
A careful examination reveals that the question asks for information about
employees This information is contained in the EMPLOYEES table
3 The word “unique” should guide you to use the DISTINCT keyword
4 Combining Steps 2 and 3, you can construct the following SQL statement:
select distinct department_id
from employees;
5 As shown in the following illustration, this query returns 12 rows Notice that
the third row is empty This is a null value in the DEPARTMENT_ID column
6 The answer to the first question is therefore: Eleven unique departments have
employees working in them, but at least one employee has not been assigned
to a department
Question 2: How many countries are there in the Europe region?
1 This question comprises two parts Consider the REGIONS table, which
contains four regions each uniquely identified by a REGION_ID value, and
the COUNTRIES table, which has a REGION_ID column indicating which
region a country belongs to