Creating an Inner Join with INNER JOIN An inner join: ◆ Uses a comparison operator ( = , <> , < , <= , > , or >= ) to match rows from two tables based on the values in common columns from each table. You can retrieve all rows in which the author identifier (the column au_id ) is the same in both the tables authors and title_authors , for example. ◆ Returns a result that contains only joined rows that satisfy the join condition(s). ◆ Is the most common type of join. To create an inner join: ◆ Type: SELECT columns FROM table1 INNER JOIN table2 ON join_conditions 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. join_conditions specifies one or more join conditions to be evaluated for each pair of joined rows. A join condition takes this form: [table1.]column op [table2.]column op usually is = but can be any compari- son operator: = , <> , < , <= , > , or >= (refer to Table 4.2 in Chapter 4). You can com- bine multiple join conditions with AND or OR ; see “Combining and Negating Conditions with AND, OR, and NOT ” in Chapter 4. ✔ Tips ■ To create an inner join of three or more tables by using JOIN syntax, type: SELECT columns FROM table1 INNER JOIN table2 ON join_condition1 INNER JOIN table3 ON join_condition2 Using WHERE syntax, type: SELECT columns FROM table1, table2, WHERE join_condition1 AND join_condition2 ■ If you’re using WHERE syntax and you omit a join condition accidentally, you’ll create a cross join. If the affected tables are large production tables, you’ll have a “runaway query” that you might have to ask your database administrator to kill. ■ By default, JOIN (without CROSS , NATURAL , OUTER , or any other modifiers) is equiva- lent to INNER JOIN . 210 Chapter 7 Creating an Inner Join with INNER JOIN ■ You can use WHERE syntax or JOIN syntax in Microsoft Access, but if you use JOIN syntax in joins that involve three or more tables, Access requires you to nest joins by using the following general syntax: SELECT columns FROM table1 INNER JOIN (table2 INNER JOIN (table3 INNER JOIN (table4 INNER JOIN ) ON table3.column3 op table4.column4) ON table2.column2 op table3.column3) ON table1.column1 op table2.column2; (Other DBMSs also let you nest joins by using parentheses, but Access requires it.) Oracle 8i doesn’t support JOIN syntax; use WHERE joins instead. Oracle 9i and later support JOIN syntax. Listing 7.7 joins two tables on the column au_id to list the books that each author wrote (or cowrote). Each author’s au_id in the table authors matches zero or more rows in the table title_authors . See Figure 7.7 for the result. Note that author A07 (Paddy O’Furniture) is omitted from the result because he has written no books and so has no matching rows in title_authors . ✔ Tip ■ Using WHERE syntax, Listing 7.7 is equiva- lent to: SELECT a.au_id, a.au_fname, a.au_lname, ta.title_id FROM authors a, title_authors ta WHERE a.au_id = ta.au_id ORDER BY a.au_id ASC, ta.title_id ASC; 211 Joins Creating an Inner Join with INNER JOIN Listing 7.7 List the books that each author wrote (or cowrote). See Figure 7.7 for the result. SELECT a.au_id, a.au_fname, a.au_lname, ta.title_id FROM authors a INNER JOIN title_authors ta ON a.au_id = ta.au_id ORDER BY a.au_id ASC, ta.title_id ASC; Listing au_id au_fname au_lname title_id A01 Sarah Buchman T01 A01 Sarah Buchman T02 A01 Sarah Buchman T13 A02 Wendy Heydemark T06 A02 Wendy Heydemark T07 A02 Wendy Heydemark T10 A02 Wendy Heydemark T12 A03 Hallie Hull T04 A03 Hallie Hull T11 A04 Klee Hull T04 A04 Klee Hull T05 A04 Klee Hull T07 A04 Klee Hull T11 A05 Christian Kells T03 A06 Kellsey T08 A06 Kellsey T09 A06 Kellsey T11 Figure 7.7 Result of Listing 7.7. Listing 7.8 joins two tables on the column pub_id to list each book’s title name and ID, and each book’s publisher name and ID. Note that the join is necessary to retrieve only the publisher name (the fourth column in the result); all the other three columns are available in the table titles . See Figure 7.8 for the result. ✔ Tip ■ Using WHERE syntax, Listing 7.8 is equiva- lent to: SELECT t.title_id, t.title_name, t.pub_id, p.pub_name FROM titles t, publishers p WHERE p.pub_id = t.pub_id ORDER BY t.title_name ASC; 212 Chapter 7 Creating an Inner Join with INNER JOIN Listing 7.8 List each book’s title name and ID and each book’s publisher name and ID. See Figure 7.8 for the result. SELECT t.title_id, t.title_name, t.pub_id, p.pub_name FROM titles t INNER JOIN publishers p ON p.pub_id = t.pub_id ORDER BY t.title_name ASC; Listing title_id title_name pub_id pub_name T01 1977! P01 Abatis Publishers T02 200 Years of German Humor P03 Schadenfreude Press T03 Ask Your System Administrator P02 Core Dump Books T04 But I Did It Unconsciously P04 Tenterhooks Press T05 Exchange of Platitudes P04 Tenterhooks Press T06 How About Never? P01 Abatis Publishers T07 I Blame My Mother P03 Schadenfreude Press T08 Just Wait Until After School P04 Tenterhooks Press T09 Kiss My Boo-Boo P04 Tenterhooks Press T10 Not Without My Faberge Egg P01 Abatis Publishers T11 Perhaps It's a Glandular Problem P04 Tenterhooks Press T12 Spontaneous, Not Annoying P01 Abatis Publishers T13 What Are The Civilian Applications? P03 Schadenfreude Press Figure 7.8 Result of Listing 7.8. Listing 7.9 uses two join conditions to list the authors who live in the same city and state as some publisher (any publisher). See Figure 7.9 for the result. Note that this query is a natural join on the identically named, nonkey columns city and state in the two tables (see “Creating a Natural Join with NATURAL JOIN ” earlier in this chapter). An equivalent query is: SELECT a.au_id, a.au_fname, a.au_lname, a.city, a.state FROM authors a NATURAL JOIN publishers p ORDER BY a.au_id ASC; ✔ Tip ■ Using WHERE syntax, Listing 7.9 is equiva- lent to: SELECT a.au_id, a.au_fname, a.au_lname, a.city, a.state FROM authors a, publishers p WHERE a.city = p.city AND a.state = p.state ORDER BY a.au_id ASC; 213 Joins Creating an Inner Join with INNER JOIN Listing 7.9 List the authors who live in the same city and state in which a publisher is located. See Figure 7.9 for the result. SELECT a.au_id, a.au_fname, a.au_lname, a.city, a.state FROM authors a INNER JOIN publishers p ON a.city = p.city AND a.state = p.state ORDER BY a.au_id; Listing au_id au_fname au_lname city state A03 Hallie Hull San Francisco CA A04 Klee Hull San Francisco CA A05 Christian Kells New York NY Figure 7.9 Result of Listing 7.9. Listing 7.10 combines an inner join with WHERE conditions to list books published in California or outside the large North American countries; see “Filtering Rows with WHERE ” in Chapter 4. See Figure 7.10 for the result. ✔ Tip ■ Using WHERE syntax, Listing 7.10 is equiv- alent to: SELECT t.title_id, t.title_name, p.state, p.country FROM titles t, publishers p WHERE t.pub_id = p.pub_id AND (p.state = ‘CA’ OR p.country NOT IN (‘USA’, ‘Canada’, ‘Mexico’)) ORDER BY t.title_id ASC; 214 Chapter 7 Creating an Inner Join with INNER JOIN Listing 7.10 List the books published in California or outside the large North American countries. See Figure 7.10 for the result. SELECT t.title_id, t.title_name, p.state, p.country FROM titles t INNER JOIN publishers p ON t.pub_id = p.pub_id WHERE p.state = 'CA' OR p.country NOT IN ('USA', 'Canada', 'Mexico') ORDER BY t.title_id ASC; Listing title_id title_name state country T02 200 Years of German Humor NULL Germany T03 Ask Your System Administrator CA USA T04 But I Did It Unconsciously CA USA T05 Exchange of Platitudes CA USA T07 I Blame My Mother NULL Germany T08 Just Wait Until After School CA USA T09 Kiss My Boo-Boo CA USA T11 Perhaps It's a Glandular Problem CA USA T13 What Are The Civilian Applications? NULL Germany Figure 7.10 Result of Listing 7.10. Listing 7.11 combines an inner join with the aggregate function COUNT() and a GROUP BY clause to list the number of books that each author wrote (or cowrote). For infor- mation about aggregate functions and GROUP BY , see Chapter 6. See Figure 7.11 for the result. Note that, as in Figure 7.7, author A07 (Paddy O’Furniture) is omitted from the result because he has written no books and so has no matching rows in title_authors . See Listing 7.30 in “Creating Outer Joins with OUTER JOIN ” later in this chapter for an example that lists authors who have written no books. ✔ Tip ■ Using WHERE syntax, Listing 7.11 is equiv- alent to: SELECT a.au_id, COUNT(ta.title_id) AS “Num books” FROM authors a, title_authors ta WHERE a.au_id = ta.au_id GROUP BY a.au_id ORDER BY a.au_id ASC; 215 Joins Creating an Inner Join with INNER JOIN Listing 7.11 List the number of books that each author wrote (or cowrote). See Figure 7.11 for the result. SELECT a.au_id, COUNT(ta.title_id) AS "Num books" FROM authors a INNER JOIN title_authors ta ON a.au_id = ta.au_id GROUP BY a.au_id ORDER BY a.au_id ASC; Listing au_id Num books A01 3 A02 4 A03 2 A04 4 A05 1 A06 3 Figure 7.11 Result of Listing 7.11. Listing 7.12 uses WHERE conditions to list the advance paid for each biography. See Figure 7.12 for the result. ✔ Tip ■ Using WHERE syntax, Listing 7.12 is equiv- alent to: SELECT t.title_id, t.title_name, r.advance FROM royalties r, titles t WHERE r.title_id = t.title_id AND t.type = ‘biography’ AND r.advance IS NOT NULL ORDER BY r.advance DESC; 216 Chapter 7 Creating an Inner Join with INNER JOIN Listing 7.12 List the advance paid for each biography. See Figure 7.12 for the result. SELECT t.title_id, t.title_name, r.advance FROM royalties r INNER JOIN titles t ON r.title_id = t.title_id WHERE t.type = 'biography' AND r.advance IS NOT NULL ORDER BY r.advance DESC; Listing title_id title_name advance T07 I Blame My Mother 1000000.00 T12 Spontaneous, Not Annoying 50000.00 T06 How About Never? 20000.00 Figure 7.12 Result of Listing 7.12. Listing 7.13 uses aggregate functions and a GROUP BY clause to list the count and total advance paid for each type of book. See Figure 7.13 for the result. ✔ Tip ■ Using WHERE syntax, Listing 7.13 is equiv- alent to: SELECT t.type, COUNT(r.advance) AS “COUNT(r.advance)”, SUM(r.advance) AS “SUM(r.advance)” FROM royalties r, titles t WHERE r.title_id = t.title_id AND r.advance IS NOT NULL GROUP BY t.type ORDER BY t.type ASC; 217 Joins Creating an Inner Join with INNER JOIN Listing 7.13 List the count and total advance paid for each type of book. See Figure 7.13 for the result. SELECT t.type, COUNT(r.advance) AS "COUNT(r.advance)", SUM(r.advance) AS "SUM(r.advance)" FROM royalties r INNER JOIN titles t ON r.title_id = t.title_id WHERE r.advance IS NOT NULL GROUP BY t.type ORDER BY t.type ASC; Listing type COUNT(r.advance) SUM(r.advance) biography 3 1070000.00 children 2 0.00 computer 1 15000.00 history 3 31000.00 psychology 3 220000.00 Figure 7.13 Result of Listing 7.13. Listing 7.14 is similar to Listing 7.13, except that it uses an additional grouping column to list the count and total advance paid for each type of book by publisher. See Figure 7.14 for the result. ✔ Tip ■ Using WHERE syntax, Listing 7.14 is equiv- alent to: SELECT t.type, t.pub_id, COUNT(r.advance) AS “COUNT(r.advance)”, SUM(r.advance) AS “SUM(r.advance)” FROM royalties r, titles t WHERE r.title_id = t.title_id AND r.advance IS NOT NULL GROUP BY t.type, t.pub_id ORDER BY t.type ASC, t.pub_id ASC; 218 Chapter 7 Creating an Inner Join with INNER JOIN Listing 7.14 List the count and total advance paid for each type of book, by publisher. See Figure 7.14 for the result. SELECT t.type, t.pub_id, COUNT(r.advance) AS "COUNT(r.advance)", SUM(r.advance) AS "SUM(r.advance)" FROM royalties r INNER JOIN titles t ON r.title_id = t.title_id WHERE r.advance IS NOT NULL GROUP BY t.type, t.pub_id ORDER BY t.type ASC, t.pub_id ASC; Listing type pub_id COUNT(r.advance) SUM(r.advance) biography P01 2 70000.00 biography P03 1 1000000.00 children P04 2 0.00 computer P02 1 15000.00 history P01 1 10000.00 history P03 2 21000.00 psychology P04 3 220000.00 Figure 7.14 Result of Listing 7.14. Listing 7.15 uses a HAVING clause to list the number of coauthors of each book written by two or more authors. For information about HAVING , see “Filtering Groups with HAVING ” in Chapter 6. See Figure 7.15 for the result. ✔ Tip ■ Using WHERE syntax, Listing 7.15 is equiv- alent to: SELECT ta.title_id, COUNT(ta.au_id) AS “Num authors” FROM authors a, title_authors ta WHERE a.au_id = ta.au_id GROUP BY ta.title_id HAVING COUNT(ta.au_id) > 1 ORDER BY ta.title_id ASC; 219 Joins Creating an Inner Join with INNER JOIN Listing 7.15 List the number of coauthors of each book written by two or more authors. See Figure 7.15 for the result. SELECT ta.title_id, COUNT(ta.au_id) AS "Num authors" FROM authors a INNER JOIN title_authors ta ON a.au_id = ta.au_id GROUP BY ta.title_id HAVING COUNT(ta.au_id) > 1 ORDER BY ta.title_id ASC; Listing title_id Num authors T04 2 T07 2 T11 3 Figure 7.15 Result of Listing 7.15.