©
This document uses PHP Chinese website manual Release
到目前为止,我们的查询一次只访问了一个表。 查询可以一次访问多个表,或者用某种方式访问一个表, 而同时处理该表的多个行。 一个同时访问同一个或者不同表的多个行的查询叫连接查询。 举例来说,比如你想列出所有天气记录以及这些记录相关的城市。 要实现这个目标, 我们需要拿weather表每行的city字段和 cities表所有行的name字段进行比较, 并选取那些这些数值相匹配的行。
Note: 这里只是一个概念上的模型。 连接通常以比实际比较每个可能的配对行更高效的方式执行,但这些是用户看不到的。
这个任务可以用下面的查询来实现:
SELECT * FROM weather, cities WHERE 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, location FROM weather, cities WHERE city = name;
练习: 看看省略WHERE子句的含义是什么。
因为这些字段的名字都不一样, 所以分析器自动找出它们属于哪个表, 但是如果两个表中有重复的字段名, 你就必须使用字段全称qualify你想要的字段:
SELECT weather.city, weather.temp_lo, weather.temp_hi, weather.prcp, weather.date, cities.location FROM weather, cities WHERE cities.name = weather.city;
一般认为在连接查询里使用字段全称是很好的风格, 这样,即使在将来向其中一个表里添加了同名字段也不会引起混淆。
到目前为止,这种类型的连接查询也可以用下面这样的形式写出来:
SELECT * FROM weather INNER JOIN cities ON (weather.city = cities.name);
这个语法并非像上面那个那么常用, 我们在这里写出来是为了让你更容易了解后面的主题。
现在我们将看看如何能把Hayward记录找回来。 我们想让查询干的事是扫描weather表, 并且对每一行都找出匹配的cities表里面的行。 如果没有找到匹配的行,那么需要一些"empty values"代替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 。
练习: 还有右连接和全连接。试着找出来它们能干什么。
我们也可以把一个表和自己连接起来。 这叫self join。比如,假设我们想找出那些在其它天气记录的温度范围之外的天气记录。 这样我们就需要拿weather 表里每行的temp_lo和temp_hi字段与 weather表里其它行的temp_lo和temp_hi字段进行比较。 我们可以用下面的查询实现这个目标:
SELECT W1.city, W1.temp_lo AS low, W1.temp_hi AS high, W2.city, W2.temp_lo AS low, W2.temp_hi AS high FROM weather W1, weather W2 WHERE W1.temp_lo < W2.temp_lo AND W1.temp_hi > W2.temp_hi; city | low | high | city | low | high ---------------+-----+------+---------------+-----+------ San Francisco | 43 | 57 | San Francisco | 46 | 50 Hayward | 37 | 54 | San Francisco | 46 | 50 (2 rows)
在这里我们把 weather 表重新标记为W1和W2以区分连接的左边和右边。 你还可以用这样的别名在其它查询里节约一些敲键,比如:
SELECT * FROM weather w, cities c WHERE w.city = c.name;
以后会经常碰到这样的缩写。