They are the four cardinal arithmetic operators addition, subtraction, multiplication, and division for numeric columns; the concatenation operator for character or string columns; and t
Trang 1select region_id, country_name from countries;
4 Manually counting the country rows with a REGION_ID of 1 returned shows that there are eight countries in the Europe region as far as the HR data model
is concerned
SQL Expressions and Operators
The general form of the SELECT statement introduced the notion that columns and expressions are selectable An expression usually consists of an operation being performed on one or more column values or expressions The operators that can act upon values to form an expression depend on the underlying data type They are the four cardinal arithmetic operators (addition, subtraction, multiplication, and division) for numeric columns; the concatenation operator for character or string columns; and the addition and subtraction operators for date and timestamp columns As in regular arithmetic, there is a predefined order of evaluation (operator precedence) when more than one operator occurs in an expression Round brackets have the highest precedence Division and multiplication operations are next in the hierarchy and are evaluated before addition and subtraction, which have lowest precedence
Operators with the same level of precedence are evaluated from left to right Round brackets may therefore be used to enforce nondefault operator precedence Using brackets generously when constructing complex expressions is good practice and is encouraged It leads to readable code that is less prone to error Expressions expose a large number of useful data manipulation possibilities
Arithmetic Operators
Consider the JOB_HISTORY table, which stores the start date and end date of an employee’s term in a previous job role It may be useful for tax or pension purposes to calculate how long an employee worked in that role This information can be obtained using an arithmetic expression Several elements of both the SQL statement and the results returned from Figure 9-5 warrant further discussion
The SELECT clause specifies five elements The first four are regular columns of the JOB_HISTORY table, while the latter provides the source information required to calculate the number of days that an employee filled a particular position Consider employee number 176 on the ninth row of output This employee started as a Sales Manager on January 1, 1999, and ended employment on December 31, 1999
Therefore, this employee worked for exactly one year, which, in 1999, consisted of
365 days
Trang 2The number of days for which an employee was employed can be calculated by
using the fifth element in the SELECT clause, which is an expression This expression
demonstrates that arithmetic performed on columns containing date information
returns numeric values that represent a certain number of days
To enforce operator precedence of the subtraction operation, the subexpression
end_date-start_date is enclosed in round brackets Adding 1 makes the result inclusive
of the final day
TIP As you practice SQL on your test database environment, you may
encounter two infamous Oracle errors: “ORA-00923: FROM keyword not
found where expected” and “ORA-00942: table or view does not exist.”
These usually indicate spelling or punctuation errors, such as missing
enclosing quotes around character literals
Expression and Column Aliasing
Figure 9-5 introduced a new concept called column aliasing Notice that the expression
has a meaningful heading named Days Employed This heading is an alias An alias is
Figure 9-5 Arithmetic expression to calculate number of days worked
Trang 3marks are necessary for two reasons First, this alias is made up of more than one word Second, case preservation of an alias is only possible if the alias is double quoted If a multiworded space-separated alias is specified, an “ORA-00923: FROM keyword not found where expected” error is returned if it is not double quoted SQL offers a more
formalized way of inserting aliases by inserting the AS keyword between the column
or expression and the alias as shown in the first line of this query:
SELECT EMPLOYEE_ID AS "Employee ID",
JOB_ID AS "Occupation",
START_DATE, END_DATE,
(END_DATE-START_DATE)+1 "Days Employed"
FROM JOB_HISTORY;
Character and String Concatenation Operator
The double pipe symbols || represent the character concatenation operator This
operator is used to join character expressions or columns together to create a larger character expression Columns of a table may be linked to each other or to strings of literal characters to create one resultant character expression
The concatenation operator is flexible enough to be used multiple times and almost anywhere in a character expression Consider the following query:
SELECT 'THE '||REGION_NAME||' region is on Planet Earth' "Planetary Location", FROM REGIONS;
Here, the character literal “The” is concatenated to the contents of the REGION_NAME column This new string of characters is further concatenated to the character literal
“region is on Planet Earth”, and the entire expression is aliased with the friendly heading “Planetary Location”
Literals and the DUAL Table
Literals are commonly used in expressions and refer to numeric, character, or date and time values found in SELECT clauses that do not originate from any database object Concatenating character literals to existing column data can be useful, but what about processing literals that have nothing to do with existing column data? To ensure relational consistency, Oracle offers a clever solution to the problem of using the database
to evaluate expressions that have nothing to do with any tables or columns To get the database to evaluate an expression, a syntactically legal SELECT statement must be submitted What if you wanted to know the sum of two numeric literals? Oracle solves the problem of relational interaction with the database operating on literal expressions
by providing a special single-rowed, single-columned table called DUAL
Trang 4Recall the DUAL table described in Figure 9-1 It contains one column called
DUMMY of the character data type You can execute the query SELECT * FROM
DUAL, and the data value “X” is returned as the contents of the DUMMY column
Testing complex expressions during development, by querying the dual table, is an
effective method to evaluate whether these expressions are correct Literal expressions
can be queried from any table, but remember that the expression will be processed
for every row in the table, while querying the DUAL table returns only one row
select 'literal '||'processing using the REGIONS table'
from regions;
select 'literal '||'processing using the DUAL table'
from dual;
The first statement will return four lines in the results set, since there are four rows of
data in the REGIONS table, while the second returns only one row
Two Single Quotes or the Alternative Quote Operator
The literal character strings concatenated so far have been singular words prepended
and appended to column expressions These character literals are specified using
single quotation marks For example:
select 'I am a character literal string' from dual;
What about character literals that contain single quotation marks? Plurals pose a
particular problem for character literal processing Consider the following statement:
select 'Plural's have one quote too many' from dual;
Executing this statement causes an ORA-00923 Oracle error to be generated So,
how are words that contain single quotation marks dealt with? There are essentially
two mechanisms available The most popular of these is to add an additional single
quotation mark next to each naturally occurring single quotation mark in the character
string The following statement demonstrates how the previous error is avoided by
replacing the character literal 'Plural's with the literal 'Plural''s
select 'Plural''s have one quote too many' from dual;
Using two single quotes to handle each naturally occurring single quote in a
character literal can become messy and error prone as the number of affected literals
increases Oracle offers a neat way to deal with this type of character literal in the form
of the alternative quote (q) operator The problem is that Oracle chose the single
quote character as the special symbol with which to enclose or wrap other character
literals These character-enclosing symbols could have been anything other than single
quotation marks
Bearing this in mind, consider the alternative quote (q) operator The q operator
enables you to choose from a set of possible pairs of wrapping symbols for character
literals as alternatives to the single quote symbols The options are any single-byte or
Trang 5SELECT q'[Even square brackets' [] can be used for Plural's]' "q[]"
FROM DUAL;
SELECT q'XWhat about UPPER CASE X for Plural'sX' "qX"
FROM DUAL;
The syntax of the alternative quote operator is as follows:
q'delimiter character literal which may include single quotes delimiter'
where delimiter can be any character or bracket The first and second examples show
the use of angle and square brackets as character delimiters, while the third example demonstrates how an uppercase “X” has been used as the special character delimiter symbol through the alternative quote operator Note that the “X” character can itself
be included in the string—so long as it is not followed by a quotation mark
NULL Is Nothing
Null refers to an absence of data A row that contains a null value lacks data for that
column Null is formally defined as a value that is unavailable, unassigned, unknown,
or inapplicable Failure to heed the special treatment that null values require will almost certainly lead to an error, or worse, an inaccurate answer This section focuses
on interacting with null column data with the SELECT statement and its impact on expressions
Not Null and Nullable Columns
Tables store rows of data that are divided into one or more columns These columns have names and data types associated with them Some of them are constrained by database rules to be mandatory columns It is compulsory for some data to be stored
in the NOT NULL columns in each row When columns of a table, however, are not compelled by the database constraints to hold data for a row, these columns run the risk of being empty
TIP Any arithmetic calculation with a NULL value always returns NULL.
Oracle offers a mechanism for interacting arithmetically with NULL values using the general functions discussed in Chapter 10 Division by a null value results in null, unlike division by zero, which results in an error When a null is encountered by the character concatenation operator, however, it is simply ignored The character
Trang 6concatenation operators ignore null, while the arithmetic operations involving null
values always result in null
Foreign Keys and Nullable Columns
Data model design sometimes leads to problematic situations when tables are related
to each other via a primary and foreign key relationship, but the column that the
foreign key is based on is nullable
The DEPARTMENTS table has, as its primary key, the DEPARTMENT_ID column
The EMPLOYEES table has a DEPARTMENT_ID column that is constrained by its
foreign key relationship to the DEPARTMENT_ID column in the DEPARTMENTS
table This means that no record in the EMPLOYEES table is allowed to have in its
DEPARTMENT_ID column a value that is not in the DEPARTMENTS table This
referential integrity forms the basis for third normal form and is critical to overall
database integrity
But what about NULL values? Can the DEPARTMENT_ID column in the
DEPARTMENTS table contain nulls? The answer is no Oracle insists that any column
that is a primary key is implicitly constrained to be mandatory But what about
implicit constraints on foreign key columns? This is a quandary for Oracle, since in
order to remain flexible and cater to the widest audience, it cannot insist that columns
related through referential integrity constraints must be mandatory Further, not all
situations demand this functionality
The DEPARTMENT_ID column in the EMPLOYEES table is actually nullable
Therefore, the risk exists that there are records with null DEPARTMENT_ID values
present in this table In fact, there are such records in the EMPLOYEES table The HR
data model allows employees, correctly or not, to belong to no department When
performing relational joins between tables, it is entirely possible to miss or exclude
certain records that contain nulls in the join column Chapter 12 discusses ways to
deal with this challenge
Exercise 9-2: Construct Expressions In this exercise you will construct two
queries to display results with an appropriate layout, one from the WEBSTORE schema
and the other from the HR schema
1 Query the WEBSTORE.CUSTOMERS table to retrieve a list of the format: X
has been a member for Y days, where X is the CUSTOMER_NAME and Y is
the number of days between today and the day the customer joined Alias the
expression: Customer Loyalty
2 Add a character string expression that concatenates string literals around the
CUSTOMER_NAME value and the date expression A possible solution is
select customer_name||' has been a member for: '||(sysdate-join_date)||'
days.' "Customer Loyalty" from customers;
3 Query the HR.JOBS table and return a single expression of the form The Job
Id for the <job_title's> job is: <job_id> Take note that the job_title should
have an apostrophe and an “s” appended to it to read more naturally A
sample of this output for the organization president is: “The Job Id for the
Trang 7it by concatenating the literal “The Job Id for the” to the JOB_TITLE column This string is then concatenated to the literal “‘s job is: ”, which is further concatenated to the JOB_ID column An additional single quotation mark is added to yield the SELECT statement that follows:
select 'The Job Id for the '||job_title||'''s job is: '||job_id
AS "Job Description" from jobs;
Limit the Rows Retrieved by a Query
One of the cornerstone principles in relational theory is selection Selection is actualized
using the WHERE clause of the SELECT statement, sometimes referred to as the predicate
Conditions that restrict the dataset returned take many forms and operate on columns as well as expressions Only rows that conform to these conditions are returned Conditions restrict rows using comparison operators in conjunction with columns and literal values Boolean operators provide a mechanism to specify multiple conditions to restrict the rows returned Boolean, conditional, concatenation, and arithmetic operators are discussed to establish their order of precedence when they are encountered in a SELECT statement
The WHERE Clause
The WHERE clause extends the SELECT statement by providing the ability to restrict
rows returned based on one or more conditions Querying a table with just the SELECT and FROM clauses results in every row of data stored in the table being returned Using the DISTINCT keyword, duplicate values are excluded, and the resultant rows are restricted to some degree What if very specific information is required from a table, for example, only the data where a column contains a specific value? How would you retrieve the countries that belong to the Europe region from the COUNTRIES table? What about retrieving just those employees who work as sales representatives? These questions are answered using the WHERE clause to specify exactly which rows must be returned The format of the SQL SELECT statement that includes the WHERE clause is
SELECT *|{[DISTINCT] column|expression [alias], }
FROM table
[WHERE condition(s)];
The WHERE clause always follows the FROM clause The square brackets indicate that the WHERE clause is optional One or more conditions may be simultaneously applied to restrict the result set A condition is specified by comparing two terms using
a conditional operator These terms may be column values, literals, or expressions The
Trang 8equality operator is most commonly used to restrict result sets An example of using a
WHERE clause is shown next:
select country_name
from countries
where region_id=3;
This example projects the COUNTRY_NAME column from the COUNTRIES table
Instead of selecting every row, the WHERE clause restricts the rows returned to only
those containing a 3 in the REGION_ID column
Numeric-Based Conditions
Conditions must be formulated appropriately for different column data types The
conditions restricting rows based on numeric columns can be specified in several
different ways Consider the SALARY column in the EMPLOYEES table This column
has a data type of NUMBER(8,2) The SALARY column can be restricted as follows:
select last_name, salary from employees where salary = 10000;
The LAST_NAME and SALARY values of the employees who earn $10,000 are retrieved,
since the data types on either side of the operator match and are compatible
A numeric column can be compared to another numeric column in the same row
to construct a WHERE clause condition, as the following query demonstrates:
select last_name, salary from employees
where salary = department_id;
This WHERE clause is too restrictive and results in no rows being selected because the
range of SALARY values is 2100 to 999999.99, and the range of DEPARTMENT_ID
values is 10 to 110 Since there is no overlap in the range of DEPARTMENT_ID and
SALARY values, there are no rows that satisfy this condition and therefore nothing is
returned
WHERE clause conditions may also be used to compare numeric columns and
expressions or to compare expressions to other expressions:
select last_name, salary from employees
where salary = department_id*100;
select last_name, salary from employees
where salary/10 = department_id*10;
The first example compares the SALARY column with DEPARTMENT_ID*100 for
each row The second example compares two expressions Notice that the conditions
in both examples are algebraically identical, and the same dataset is retrieved when
both are executed
Character-Based Conditions
Conditions determining which rows are selected based on character data are specified
by enclosing character literals in the conditional clause, within single quotes The JOB_ID
column in the EMPLOYEES table has a data type of VARCHAR2(10) Suppose you
Trang 9be raised Remember that character literal data is case sensitive, so the following WHERE clauses are not equivalent
Clause 1: where job_id=SA_REP
Clause 2: where job_id='Sa_Rep'
Clause 3: where job_id='sa_rep'
Clause 1 generates an “ORA-00904: ‘SA_REP’: invalid identifier” error, since the literal SA_REP is not wrapped in single quotes Clause 2 and Clause 3 are syntactically correct but not equivalent Further, neither of these clauses yields any data, since there are no rows in the EMPLOYEES table having JOB_ID column values that are either Sa_Rep or sa_rep
Character-based conditions are not limited to comparing column values with literals They may also be specified using other character columns and expressions Character-based expressions may form either one or both parts of a condition
separated by a conditional operator These expressions can be formed by
concatenating literal values with one or more character columns The following four clauses demonstrate some of the options for character-based conditions:
Clause 1: where 'A '||last_name||first_name = 'A King'
Clause 2: where first_name||' '||last_name = last_name||'
'||first_name
Clause 3: where 'SA_REP'||'King' = job_id||last_name
Clause 4: where job_id||last_name ='SA_REP'||'King'
Clause 1 concatenates the string literal “A” to the LAST_NAME and FIRST_NAME columns This expression is compared to the literal “A King” Clause 2 demonstrates that character expressions may be placed on both sides of the conditional operator Clause 3 illustrates that literal expressions may also be placed on the left of the conditional operator It is logically equivalent to clause 4, which has swapped the operands in clause 3 around Both clauses 3 and 4 identically restrict the results
Date-Based Conditions
DATE columns are useful for storing date and time information Date literals must be enclosed in single quotation marks just like character data When used in conditional WHERE clauses, date columns may be compared to other date columns, literals, or expressions The literals are automatically converted into DATE values based on the default date format, which is DD-MON-RR If a literal occurs in an expression
involving a DATE column, it is automatically converted into a date value using the default format mask DD represents days, MON represents the first three letters of a month, and RR represents a Year 2000–compliant year (that is, if RR is between 50
Trang 10and 99, then the Oracle server returns the previous century, or else it returns the
current century) The full four-digit year, YYYY, can also be specified Consider the
following four WHERE clauses:
Clause 1: where start_date = end_date;
Clause 2: where start_date = '01-JAN-2001';
Clause 3: where start_date = '01-JAN-01';
Clause 4: where start_date = '01-JAN-99';
The first clause tests equality between two DATE columns Rows that contain the
same values in their START_DATE and END_DATE columns will be returned Note,
however, that DATE values are only equal to each other if there is an exact match
between all their components, including day, month, year, hours, minutes, and
seconds Chapter 10 discusses the details of storing DATE values Until then, don’t
worry about the hours, minutes, and seconds components In the second WHERE
clause, the START_DATE column is compared to the character literal: ‘01-JAN-2001’
The entire four-digit year component (YYYY) has been specified This is acceptable
to the Oracle server The third condition is equivalent to the second, since the literal
‘01-JAN-01’ is converted to the date value 01-JAN-2001 This is due to the RR component
being less than 50, so the current (twenty-first) century, 20, is prefixed to the year
RR component to provide a century value The century component for the literal
‘01-JAN-99’ becomes the previous century (19) and is converted to a date value of
01-JAN-1999 for the fourth condition, since the RR component, 99, is greater than 50
Date arithmetic using the addition and subtraction operators is supported An
expression like END_DATE – START_DATE returns the number of days between
START_DATE and END_DATE START_DATE + 30 returns a date 30 days later than
START_DATE
EXAM TIP Conditional clauses compare two terms using comparison
operators Knowing the data types of the terms is important so that they
can be enclosed in single quotes, if necessary
Comparison Operators
The equality operator is generally used to illustrate the concept of restricting rows
using a WHERE clause There are several alternative operators that may also be used
The inequality operators like “less than” or “greater than or equal to” may be used to
return rows conforming to inequality conditions The BETWEEN operator facilitates
range-based comparison to test whether a column value lies between two values The
IN operator tests set membership, so a row is returned if the column value tested in
the condition is a member of a set of literals The pattern matching comparison
operator LIKE is extremely powerful, allowing components of character column
data to be matched to literals conforming to a specific pattern The last comparison
operator discussed in this section is the IS NULL operator, which returns rows where
the column value contains a null value These operators may be used in any combination
in the WHERE clause