1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>2.6. Joins Between Tables</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="tutorial-select.html" title="2.5. Querying a Table" /><link rel="next" href="tutorial-agg.html" title="2.7. Aggregate Functions" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">2.6. Joins Between Tables</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="tutorial-select.html" title="2.5. Querying a Table">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="tutorial-sql.html" title="Chapter 2. The SQL Language">Up</a></td><th width="60%" align="center">Chapter 2. The <acronym class="acronym">SQL</acronym> Language</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="tutorial-agg.html" title="2.7. Aggregate Functions">Next</a></td></tr></table><hr /></div><div class="sect1" id="TUTORIAL-JOIN"><div class="titlepage"><div><div><h2 class="title" style="clear: both">2.6. Joins Between Tables <a href="#TUTORIAL-JOIN" class="id_link">#</a></h2></div></div></div><a id="id-1.4.4.7.2" class="indexterm"></a><p>
3 Thus far, our queries have only accessed one table at a time.
4 Queries can access multiple tables at once, or access the same
5 table in such a way that multiple rows of the table are being
6 processed at the same time. Queries that access multiple tables
7 (or multiple instances of the same table) at one time are called
8 <em class="firstterm">join</em> queries. They combine rows from one table
9 with rows from a second table, with an expression specifying which rows
10 are to be paired. For example, to return all the weather records together
11 with the location of the associated city, the database needs to compare
12 the <code class="structfield">city</code>
13 column of each row of the <code class="structname">weather</code> table with the
14 <code class="structfield">name</code> column of all rows in the <code class="structname">cities</code>
15 table, and select the pairs of rows where these values match.<a href="#ftn.id-1.4.4.7.3.6" class="footnote"><sup class="footnote" id="id-1.4.4.7.3.6">[4]</sup></a>
16 This would be accomplished by the following query:
18 </p><pre class="programlisting">
19 SELECT * FROM weather JOIN cities ON city = name;
22 </p><pre class="screen">
23 city | temp_lo | temp_hi | prcp | date | name | location
24 ---------------+---------+---------+------+------------+---------------+-----------
25 San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53)
26 San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53)
31 Observe two things about the result set:
32 </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
33 There is no result row for the city of Hayward. This is
34 because there is no matching entry in the
35 <code class="structname">cities</code> table for Hayward, so the join
36 ignores the unmatched rows in the <code class="structname">weather</code> table. We will see
37 shortly how this can be fixed.
38 </p></li><li class="listitem"><p>
39 There are two columns containing the city name. This is
40 correct because the lists of columns from the
41 <code class="structname">weather</code> and
42 <code class="structname">cities</code> tables are concatenated. In
43 practice this is undesirable, though, so you will probably want
44 to list the output columns explicitly rather than using
45 <code class="literal">*</code>:
46 </p><pre class="programlisting">
47 SELECT city, temp_lo, temp_hi, prcp, date, location
48 FROM weather JOIN cities ON city = name;
50 </p></li></ul></div><p>
52 Since the columns all had different names, the parser
53 automatically found which table they belong to. If there
54 were duplicate column names in the two tables you'd need to
55 <em class="firstterm">qualify</em> the column names to show which one you
58 </p><pre class="programlisting">
59 SELECT weather.city, weather.temp_lo, weather.temp_hi,
60 weather.prcp, weather.date, cities.location
61 FROM weather JOIN cities ON weather.city = cities.name;
64 It is widely considered good style to qualify all column names
65 in a join query, so that the query won't fail if a duplicate
66 column name is later added to one of the tables.
68 Join queries of the kind seen thus far can also be written in this
71 </p><pre class="programlisting">
77 This syntax pre-dates the <code class="literal">JOIN</code>/<code class="literal">ON</code>
78 syntax, which was introduced in SQL-92. The tables are simply listed in
79 the <code class="literal">FROM</code> clause, and the comparison expression is added
80 to the <code class="literal">WHERE</code> clause. The results from this older
81 implicit syntax and the newer explicit
82 <code class="literal">JOIN</code>/<code class="literal">ON</code> syntax are identical. But
83 for a reader of the query, the explicit syntax makes its meaning easier to
84 understand: The join condition is introduced by its own key word whereas
85 previously the condition was mixed into the <code class="literal">WHERE</code>
86 clause together with other conditions.
87 </p><a id="id-1.4.4.7.7" class="indexterm"></a><p>
88 Now we will figure out how we can get the Hayward records back in.
89 What we want the query to do is to scan the
90 <code class="structname">weather</code> table and for each row to find the
91 matching <code class="structname">cities</code> row(s). If no matching row is
92 found we want some <span class="quote">“<span class="quote">empty values</span>”</span> to be substituted
93 for the <code class="structname">cities</code> table's columns. This kind
94 of query is called an <em class="firstterm">outer join</em>. (The
95 joins we have seen so far are <em class="firstterm">inner joins</em>.)
96 The command looks like this:
98 </p><pre class="programlisting">
100 FROM weather LEFT OUTER JOIN cities ON weather.city = cities.name;
103 </p><pre class="screen">
104 city | temp_lo | temp_hi | prcp | date | name | location
105 ---------------+---------+---------+------+------------+---------------+-----------
106 Hayward | 37 | 54 | | 1994-11-29 | |
107 San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53)
108 San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53)
112 This query is called a <em class="firstterm">left outer
113 join</em> because the table mentioned on the left of the
114 join operator will have each of its rows in the output at least
115 once, whereas the table on the right will only have those rows
116 output that match some row of the left table. When outputting a
117 left-table row for which there is no right-table match, empty (null)
118 values are substituted for the right-table columns.
119 </p><p><strong>Exercise: </strong>
120 There are also right outer joins and full outer joins. Try to
121 find out what those do.
122 </p><a id="id-1.4.4.7.10" class="indexterm"></a><a id="id-1.4.4.7.11" class="indexterm"></a><p>
123 We can also join a table against itself. This is called a
124 <em class="firstterm">self join</em>. As an example, suppose we wish
125 to find all the weather records that are in the temperature range
126 of other weather records. So we need to compare the
127 <code class="structfield">temp_lo</code> and <code class="structfield">temp_hi</code> columns of
128 each <code class="structname">weather</code> row to the
129 <code class="structfield">temp_lo</code> and
130 <code class="structfield">temp_hi</code> columns of all other
131 <code class="structname">weather</code> rows. We can do this with the
134 </p><pre class="programlisting">
135 SELECT w1.city, w1.temp_lo AS low, w1.temp_hi AS high,
136 w2.city, w2.temp_lo AS low, w2.temp_hi AS high
137 FROM weather w1 JOIN weather w2
138 ON w1.temp_lo < w2.temp_lo AND w1.temp_hi > w2.temp_hi;
141 </p><pre class="screen">
142 city | low | high | city | low | high
143 ---------------+-----+------+---------------+-----+------
144 San Francisco | 43 | 57 | San Francisco | 46 | 50
145 Hayward | 37 | 54 | San Francisco | 46 | 50
149 Here we have relabeled the weather table as <code class="literal">w1</code> and
150 <code class="literal">w2</code> to be able to distinguish the left and right side
151 of the join. You can also use these kinds of aliases in other
152 queries to save some typing, e.g.:
153 </p><pre class="programlisting">
155 FROM weather w JOIN cities c ON w.city = c.name;
157 You will encounter this style of abbreviating quite frequently.
158 </p><div class="footnotes"><br /><hr style="width:100; text-align:left;margin-left: 0" /><div id="ftn.id-1.4.4.7.3.6" class="footnote"><p><a href="#id-1.4.4.7.3.6" class="para"><sup class="para">[4] </sup></a>
159 This is only a conceptual model. The join is usually performed
160 in a more efficient manner than actually comparing each possible
161 pair of rows, but this is invisible to the user.
162 </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="tutorial-select.html" title="2.5. Querying a Table">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="tutorial-sql.html" title="Chapter 2. The SQL Language">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="tutorial-agg.html" title="2.7. Aggregate Functions">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2.5. Querying a Table </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="40%" align="right" valign="top"> 2.7. Aggregate Functions</td></tr></table></div></body></html>