到目前為止,我們的查詢一次只訪問了一個表。查詢可以一次訪問多個表,或者用某種方式訪問一個表,而同時處理該表的多個行。一個同時訪問同一個或者不同表的多個行的查詢叫連接查詢。舉例來說,比如你想列出所有天氣記錄以及這些記錄相關的城市。要實現這個目標,我們需要拿 weather 表每行的 city 字段和 cities 表所有行的 name 字段進行比較,并選取那些這些數值相匹配的行。
【注意】這里只是一個概念上的模型。連接通常以比實際比較每個可能的配對行更高效的方式執行,但這些是用戶看不到的。
這個任務可以用下面的查詢來實現:
SELECT *FROM weather, citiesWHERE city = name;
city | temp_lo | temp_hi | prcp | date | name | location ---------------+---------+---------+------+------------+---------------+-----------San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53)San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53) (2 rows)
觀察結果集的兩個方面:
-
沒有城市 Hayward 的結果行。這是因為在
cities
表里面沒有與 Hayward 匹配的行,所以連接忽略了 weather 表里的不匹配行。我們稍后將看到如何修補這個問題。 -
有兩個字段包含城市名。這是正確的,因為
weather
和cities
表的字段是接在一起的。不過,實際上我們不想要這些,因此你將可能希望明確列出輸出字段而不是使用 * :SELECT city, temp_lo, temp_hi, prcp, date, locationFROM weather, citiesWHERE city = name;
【練習】看看省略 WHERE 子句的含義是什么。
因為這些字段的名字都不一樣,所以分析器自動找出它們屬于哪個表,但是如果兩個表中有重復的字段名,你就必須使用字段全稱限定你想要的字段:
SELECT weather.city, weather.temp_lo, weather.temp_hi,weather.prcp, weather.date, cities.locationFROM weather, citiesWHERE cities.name = weather.city;
一般認為在連接查詢里使用字段全稱是很好的風格,這樣,即使在將來向其中一個表里添加了同名字段也不會引起混淆。
到目前為止,這種類型的連接查詢也可以用下面這樣的形式寫出來:
SELECT *FROM weather INNER JOIN cities ON (weather.city = cities.name);
這個語法并非像上面那個那么常用,我們在這里寫出來是為了讓你更容易了解后面的主題。
現在我們將看看如何能把 Hayward 記錄找回來。我們想讓查詢干的事是掃描 weather
表,并且對每一行都找出匹配的 cities
表里面的行。如果沒有找到匹配的行,那么需要一些"空值"代替 cities
表的字段。這種類型的查詢叫 外連接(我們在此之前看到的連接都是內連接)。這樣的命令看起來像這樣:
SELECT *FROM weather LEFT OUTER JOIN cities ON (weather.city = cities.name);city | temp_lo | temp_hi | prcp | date | name | location ---------------+---------+---------+------+------------+---------------+-----------Hayward | 37 | 54 | | 1994-11-29 | |San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53)San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53) (3 rows)
這個查詢是一個左外連接,因為連接操作符(LEFT OUTER JOIN)左邊的表中的行在輸出中至少出現一次,而右邊的表中的行只輸出那些與左邊的表有匹配的行。如果輸出的左表中的行沒有右表中的行與其對應,那么右表中的字段將填充為 NULL 。
-- 更多信息參考http://www.infocool.net/PostgreSQL/index.htm
【練習】還有右連接和全連接。試著找出來它們能干什么。
SELECT W1.city, W1.temp_lo AS low, W1.temp_hi AS high,W2.city, W2.temp_lo AS low, W2.temp_hi AS highFROM weather W1, weather W2WHERE W1.temp_lo < W2.temp_loAND W1.temp_hi > W2.temp_hi;city | low | high | city | low | high ---------------+-----+------+---------------+-----+------San Francisco | 43 | 57 | San Francisco | 46 | 50Hayward | 37 | 54 | San Francisco | 46 | 50 (2 rows)
在這里我們把 weather 表重新標記為 W1 和 W2 以區分連接的左邊和右邊。你還可以用這樣的別名在其它查詢里節約一些敲鍵,比如:
SELECT *FROM weather w, cities cWHERE w.city = c.name;
以后會經常碰到這樣的縮寫。