To create a join by using JOIN: ◆ Type: SELECT columns FROM table1 join_type table2 ON join_conditions [WHERE search_condition] [GROUP BY grouping_columns] [HAVING search_condition] [ORD
Trang 1Creating Joins with
JOIN or WHERE
You have two alternative ways of specifying
a join: by using JOINsyntax or WHEREsyntax
SQL-92 and later standards prescribe JOIN
syntax, but older standards prescribe WHERE;
hence, both JOINandWHEREare used widely
and are legal in most DBMSs
This section explains the general syntax for
JOINandWHEREjoins that involve two tables
The actual syntax that you’ll use in real
queries will vary by the join type, the
num-ber of columns joined, the numnum-ber of tables
joined, and the syntax requirements of your
DBMS The syntax diagrams and examples
in the following sections show you how to
create specific joins
To create a join by using JOIN:
◆ Type:
SELECT columns FROM table1 join_type table2
ON join_conditions [WHERE search_condition]
[GROUP BY grouping_columns]
[HAVING search_condition]
[ORDER BY sort_columns];
columns is one or more comma-separated
expressions or column names from table1
or table2 If table1 and table2 have a
col-umn name in common, you must qualify all references to these columns through-out the query to prevent ambiguity; see
“Qualifying Column Names” earlier in this chapter
table1 and table2 are the names of the
joined tables You can alias the table names; see “Creating Table Aliases with
AS” earlier in this chapter
join_type specifies what kind of join is
performed: CROSS JOIN,NATURAL JOIN,
INNER JOIN,LEFT OUTER JOIN,RIGHT OUTER JOIN, or FULL OUTER JOIN
join_conditions specifies one or more
join conditions to be evaluated for each pair of joined rows (The ONclause isn’t allowed in cross joins and natural joins.)
A join condition takes this form:
[table1.]column op [table2.]column
compari-son operator: =,<>,<,<=,>, or >=(refer
to Table 4.2 in Chapter 4) You can com-bine multiple join conditions with AND
orOR; see “Combining and Negating Conditions with AND, OR,andNOT” in Chapter 4
TheWHEREandORDER BYclauses are covered in Chapter 4; GROUP BYand
HAVINGare covered in Chapter 6
Trang 2To create a join by using WHERE:
◆ Type:
SELECT columns FROM table1, table2 WHERE join_conditions [GROUP BY grouping_columns]
[HAVING search_condition]
[ORDER BY sort_columns];
columns, table1, and table2 have the
same meaning as in “To create a join by using JOIN” earlier in this section
join_conditions also has the same
mean-ing as in “To create a join by usmean-ing JOIN”
earlier in this chapter, except that op can
be a special symbol that indicates the join type The WHEREclause also can include (nonjoin) search conditions to filter rows; see “Filtering Rows with
WHERE” in Chapter 4
TheORDER BYclause is covered in Chapter 4; GROUP BYandHAVINGare covered in Chapter 6
Listings 7.3a and 7.3b show equivalent
queries that use JOINandWHEREsyntax
See Figure 7.3 for the result.
Listing 7.3a A join that uses JOIN syntax See
Figure 7.3 for the result.
SELECT au_fname, au_lname, a.city
FROM authors a
INNER JOIN publishers p
ON a.city = p.city ;
Listing
Listing 7.3b The same join, using WHERE syntax See
Figure 7.3 for the result.
SELECT au_fname, au_lname, a.city
FROM authors a, publishers p
WHERE a.city = p.city ;
Listing
au_fname au_lname city
- -
-Hallie Hull San Francisco
Klee Hull San Francisco
Christian Kells New York
Figure 7.3 Result of Listings 7.3a and 7.3b.
Query Execution Sequence
When your DBMS processes joins, it uses a logical sequence to execute the entire query
The DBMS:
1. Applies the join conditions in the JOINclause
2. Applies the join conditions and search conditions in the WHEREclause
3. Groups rows according to the GROUP BYclause
4. Applies the search conditions in the HAVINGclause to the groups
5. Sorts the result according to the ORDER BYclause
Trang 3✔ Tips
■ It might seem odd to use a WHEREclause
to specify join conditions, but the join
condition does act as a filter When you
join two tables, the DBMS internally pairs
every row in the left table with every row
in the right table, forming a cross join
(see the next section) The DBMS then
uses the join condition to filter rows
from the cross join (conceptually,
any-way; DBMS optimizers don’t actually
create enormous cross-joined tables for
every join)
■ The compelling reason to prefer JOIN
toWHEREsyntax is that JOINmakes the
join type explicit A LEFT OUTER JOIN Bis
clearer than, say, A *= B For the most
common type of joins—simple inner
joins—I think that WHEREsyntax is easier
to understand, however Both JOINand
WHEREsyntax are popular, so you’ll have
to learn both to read queries created by
other people
■ In a three-table join, only one table can
be used to bridge from one of the other
tables to the third table
■ TheSELECT-clause list for a join can
ref-erence all the columns in the joined tables
or any subset of the columns The list
isn’t required to contain columns from
every table in the join In a three-table
join, for example, none of the columns
from the middle table needs to be in
the list
■ Joined columns don’t need to have the same data type If the data types aren’t identical, they must be compatible or must be data types that your DBMS can convert implicitly to a common type If the data types can’t be converted implic-itly, the join condition must convert the data type explicitly by using the CAST()
function For information about implicit and explicit conversions, see “Converting Data Types with CAST()” in Chapter 5
■ If you’re using WHEREsyntax with two or more join conditions, you’ll almost always want to combine all the join conditions with AND Combining join conditions with
ORis legal, but the result is hard to inter-pret For more information about AND
andOR, see “Combining and Negating Conditions with AND, OR,andNOT” in Chapter 4
■ Most queries that use joins can be rewritten by using a subquery (a query nested within another query), and most subqueries can be rewritten as joins For information about subqueries, see Chapter 8
■ Oracle 8i and earlier don’t
support JOINsyntax; use WHERE
joins instead Oracle 9i and later support
JOINsyntax
Your DBMS might prohibit joins on columns with particular data types (especially binary and long-text data
types) Microsoft SQL Server prohibits
joins on ntext,text, and imagecolumns,
and Oracle prohibits joins on LOB
columns, for example Search your
DBMS documentation for joins.
Trang 4The USINGClause
For JOINsyntax, the SQL standard also defines a USINGclause that can be used instead of the
ONclause if the joined columns have the same name and are compared for equality:
FROM table1 join_type table2
USING (columns)
columns is a comma-separated list of one or more column names The parentheses are
required The query performs an equijoin on the named pair(s) of columns The type of join
is called a named columns join Rewriting Listing 7.3a with USING:
SELECT au_fname, au_lname, city
FROM authors
INNER JOIN publishers
USING (city);
TheUSINGclause acts like a natural join, except that you can use it if you don’t want to join
exam-ple joins only on the column cityin both tables, whereas a natural join would join on both
the columns cityandstatecommon to the tables See “Creating a Natural Join with NATURAL
JOIN” later in this chapter
USINGis a syntactic convenience that doesn’t add extra functionality to SQL AUSINGclause
always can be replicated with an ONclause in JOINsyntax or with a WHEREclause in WHEREsyntax
Microsoft Access, Microsoft SQL Server, and DB2 don’t support USING MySQL
requires the SELECTclause’s common column names to be qualified in USINGqueries
To run the preceding example, change citytoauthors.cityin the SELECTclause
Trang 5Creating a Cross Join
A cross join:
◆ Returns all possible combinations of
rows of two tables The result contains
all rows from the first table; each row
from the first table is combined with all
rows from the second table
◆ Doesn’t use a join condition To create
a cross join, omit the ONclause if you’re
using JOINsyntax, or omit the WHERE
clause if you’re using WHEREsyntax
◆ Seldom is used alone because the result
is cumbersome and hard to interpret but
does appear in some types of queries as
an intermediate result (see “Calculating
Running Statistics” and “Generating
Sequences” in Chapter 15, for example)
◆ Can produce a huge result, even with
small tables If one table has m rows and
the other has n rows, the result contains
◆ Is a computationally expensive and
time-consuming query
◆ Also is called a Cartesian product or
cross product.
To create a cross join:
◆ Type:
SELECT columns
FROM table1
CROSS JOIN table2
columns is one or more comma-separated
expressions or column names from table1
or table2 table1 and table2 are the names
of the joined tables If the tables have
some column names in common, qualify
those column names with the names of
the tables (Listing 7.4 and Figure 7.4).
Listing 7.4 A cross join displays all possible
combinations of rows from two tables See Figure 7.4 for the result.
SELECT au_id, pub_id, a.state AS "au_state", p.state AS "pub_state"
FROM authors a
CROSS JOIN publishers p;
Listing
au_id pub_id au_state pub_state - - - -A01 P01 NY NY A02 P01 CO NY A03 P01 CA NY A04 P01 CA NY A05 P01 NY NY A06 P01 CA NY A07 P01 FL NY A01 P02 NY CA A02 P02 CO CA A03 P02 CA CA A04 P02 CA CA A05 P02 NY CA A06 P02 CA CA A07 P02 FL CA A01 P03 NY NULL A02 P03 CO NULL A03 P03 CA NULL A04 P03 CA NULL A05 P03 NY NULL A06 P03 CA NULL A07 P03 FL NULL A01 P04 NY CA A02 P04 CO CA A03 P04 CA CA A04 P04 CA CA A05 P04 NY CA A06 P04 CA CA A07 P04 FL CA
Figure 7.4 Result of Listing 7.4.
Trang 6✔ Tips
■ Using WHEREsyntax, Listing 7.4 is
equiva-lent to:
SELECT au_id, pub_id,
a.state AS “au_state”,
p.state AS “pub_state”
FROM authors a, publishers p;
■ Use SELECT *to retrieve all columns
from both tables This query retrieves
all columns from the tables authors
andpublishers:
SELECT *
FROM authors
CROSS JOIN publishers;
Equivalently, usingWHEREsyntax:
SELECT *
FROM authors, publishers;
■ Use SELECT table.*to retrieve all columns
from just one of the tables The following
query retrieves all columns from the table
authorsand only the column pub_id
from the table publishers:
SELECT authors.*, p.pub_id
FROM authors
CROSS JOIN publishers p;
Equivalently, usingWHEREsyntax:
SELECT authors.*, p.pub_id
FROM authors, publishers p;
■ To find the cross product of n tables by
using JOINsyntax, type:
SELECT columns
FROM table1
CROSS JOIN table2
CROSS JOIN tableN
Equivalently, usingWHEREsyntax:
SELECT columns
FROM table1, table2, , tableN
■ Cross products often are produced mistakenly If your result contains an unexpectedly large number of rows, you might have omitted a join condition from your query accidentally
■ Although a cross product rarely is the result you want in practice, your DBMS (theoretically) generates a cross product internally as the first step in processing every join After the DBMS has the cross product, it uses the SELECT-clause list to delete columns and the join and search conditions to delete rows
■ The join
t1 CROSS JOIN t2
is equivalent to any of the following joins:
t1 INNER JOIN t2 ON 1 = 1 t1 LEFT OUTER JOIN t2 ON 1 = 1 t1 RIGHT OUTER JOIN t2 ON 1 = 1 t1 FULL OUTER JOIN t2 ON 1 = 1
any condition that always is true Inner and outer joins are covered later in this chapter
■ One practical use of cross joins is to pro-duce datasets for testing software Suppose
that you have a function that takes n argu-ments, and each argument assumes m
representative test values You can
gen-erate all m✕n test cases by finding the
cross product of n tables (one table for
each argument), in which each table has
one column and m rows (one row that
contains each test value) This method
still works if m differs for each argument.
■ Microsoft Access and DB2
supports only WHEREsyntax for cross joins To run Listing 7.4, use the state-ment given in the first Tip in this section
Oracle 8i doesn’t support JOINsyntax;
useWHEREjoins instead
Trang 7Creating a Natural Join
A natural join:
◆ Is a special case of an equijoin; it
com-pares all the columns in one table with
corresponding columns that have the
same name in the other table for
equali-ty
◆ Works only if the input tables have one
or more pairs of meaningfully comparable,
identically named columns
◆ Performs joins implicitly Don’t specify an
ONorUSINGclause in a natural join
◆ Is a syntactic convenience that can be
replicated explicitly with an ONclause
inJOINsyntax or a WHEREclause in
WHEREsyntax
To create a natural join:
◆ Type:
SELECT columns
FROM table1
NATURAL JOIN table2
columns is one or more comma-separated
expressions or column names from table1
or table2 Your DBMS might require
iden-tical column names to be qualified with
the names of the tables (see the DBMS
Tip in this section) table1 and table2 are
the names of the joined tables
The columns in table1 are joined with the
identically named columns in table2 and
compared for equality NATURAL JOIN
cre-ates natural inner joins; to create natural
outer joins, see the Tips in this section
Listing 7.5 List each book’s publisher See Figure 7.5
for the result.
SELECT title_id, pub_id, pub_name FROM publishers
NATURAL JOIN titles;
Listing
title_id pub_id pub_name - - -T01 P01 Abatis Publishers T02 P03 Schadenfreude Press T03 P02 Core Dump Books T04 P04 Tenterhooks Press T05 P04 Tenterhooks Press T06 P01 Abatis Publishers T07 P03 Schadenfreude Press T08 P04 Tenterhooks Press T09 P04 Tenterhooks Press T10 P01 Abatis Publishers T11 P04 Tenterhooks Press T12 P01 Abatis Publishers T13 P03 Schadenfreude Press
Figure 7.5 Result of Listing 7.5.
Trang 8When your DBMS runs Listing 7.5, it will
join rows in the table publisherswith rows
in the table titlesthat have equal values
in the columns publishers.pub_idand
titles.pub_id—the two columns that have
the same name in both tables See Figure 7.5
for the result
In Listing 7.6, I’ve added another join to
Listing 7.5 to retrieve the advance for each book The WHEREcondition retrieves books with advances less than $20,000 When your DBMS runs Listing 7.6, it will join the pub_id
columns in the tables publishersand
titles, and it will join the title_idcolumns
in the tables titlesandroyalties See
Figure 7.6 for the result.
✔ Tips
■ To replicate a natural join by using WHERE
syntax, use an equijoin with a WHERE
clause that uses ANDoperators to com-bine join conditions Each join condition equates each pair of columns with the same name in the input tables The equivalent WHEREqueries are (Listing 7.5):
SELECT t.title_id, t.pub_id, p.pub_name
FROM publishers p, titles t WHERE p.pub_id = t.pub_id;
and (Listing 7.6):
SELECT t.title_id, t.pub_id, p.pub_name, r.advance FROM publishers p, titles t, royalties r
WHERE p.pub_id = t.pub_id AND t.title_id = r.title_id AND r.advance < 20000;
continues on next page
Listing 7.6 List each book’s publisher and advance
for books with advances less than $20,000 See
Figure 7.6 for the result.
SELECT
title_id,
pub_id,
pub_name,
advance
FROM publishers
NATURAL JOIN titles
NATURAL JOIN royalties
WHERE advance < 20000;
Listing
title_id pub_id pub_name advance
- - -
-T01 P01 Abatis Publishers 10000
T02 P03 Schadenfreude Press 1000
T03 P02 Core Dump Books 15000
T08 P04 Tenterhooks Press 0
T09 P04 Tenterhooks Press 0
Figure 7.6 Result of Listing 7.6.
Trang 9■ To replicate a natural join by using inner
or outer JOINsyntax, use an equijoin
with an ONclause that uses ANDoperators
to combine join conditions Each join
condition equates each pair of columns
with the same name in both input
tables The equivalent JOINqueries are
(Listing 7.5):
SELECT t.title_id, t.pub_id,
p.pub_name
FROM publishers p
INNER JOIN titles t
ON p.pub_id = t.pub_id;
and (Listing 7.6):
SELECT t.title_id, t.pub_id,
p.pub_name, r.advance
FROM publishers p
INNER JOIN titles t
ON p.pub_id = t.pub_id
INNER JOIN royalties r
ON t.title_id = r.title_id
WHERE r.advance < 20000;
■ You also can replicate a natural join by using JOINsyntax with a USINGclause (see the sidebar in “Creating Joins with
JOINorWHERE” earlier in this chapter)
NATURAL JOINis a shorthand form of
USING; it forms a USINGlist consisting of exactly those column names that appear
in both tables The equivalent USING
queries are (Listing 7.5):
SELECT title_id, pub_id, pub_name
FROM publishers INNER JOIN titles USING (pub_id);
and (Listing 7.6):
SELECT title_id, pub_id, pub_name, advance FROM publishers INNER JOIN titles USING (pub_id) INNER JOIN royalties USING (title_id) WHERE advance < 20000;
■ The syntaxNATURAL JOINactually creates
an inner join: NATURAL JOINis equivalent
toNATURAL INNER JOIN You can create natural outer joins with:
NATURAL LEFT [OUTER] JOIN NATURAL RIGHT [OUTER] JOIN NATURAL FULL [OUTER] JOIN
Inner and outer joins are described later
in this chapter
Trang 10■ If you use a natural join, be certain that
all related (joinable) columns have the
same name in both tables and that all
unrelated columns have unique names
■ Natural joins make some queries shorter
and easier to understand, but be wary of
them They will return different results
unexpectedly if the columns involved in
the join are added, deleted, or renamed
without your knowledge
■ The meaning of natural join differs
slightly in the relational model (Chapter 2)
and the SQL standard In the model,
a natural join always is a join from a
foreign key to its parent key In SQL,
a natural join is a join of two tables over
all columns that have the same name (not
just key columns) See Listing 7.9 later in
this chapter for an example of a natural
join that doesn’t involve key columns
To make the model and the SQL
defini-tions of a natural join agree, a database
designer will ensure that all the foreign
keys have the same names as their
par-ent keys and that all other columns have
unique names
■ Microsoft Access, Microsoft
SQL Server, and DB2 don’t
support NATURAL JOINsyntax To run Listings 7.5 and 7.6, use either WHERE syn-tax (given in the first Tip in this section)
or equivalent JOINsyntax (given in the second Tip in this section)
Oracle 8i doesn’t support JOINsyntax;
useWHEREjoins instead
MySQL 4.1 and earlier require common
column names to be qualified in natural joins To run Listings 7.5 and 7.6, add qualifiers (Listing 7.5):
SELECT t.title_id, t.pub_id, p.pub_name FROM publishers p NATURAL JOIN titles t;
and (Listing 7.6):
SELECT t.title_id, t.pub_id, p.pub_name, r.advance FROM publishers p NATURAL JOIN titles t NATURAL JOIN royalties r WHERE r.advance < 20000;