打印

PostgreSQL 8.1 中文文档

在这个例子里,排序的顺序并非绝对清晰的,因此你可能看到 San Francisco 行随机的排序。 但是如果你使用下面的语句,那么就总是会得到上面的结果

SELECT * FROM weather
    ORDER BY city, temp_lo;
你可以要求查询的结果按照某种顺序排序, 并且消除重复的行输出:

SELECT DISTINCT city
    FROM weather;
     city
---------------
Hayward
San Francisco
(2 rows)再次声明,结果行的顺序可能是随机的。 你可以组合使用 DISTINCT 和 ORDER BY 来获取一致的结果: [2]

SELECT DISTINCT city
    FROM weather
    ORDER BY city;
Notes
[1] 虽然 SELECT * 对于把查询的结果翻出来很有用, 我们普遍认为在生产代码中这是很糟糕的风格,因为给表增加一个字段就改变了结果。

[2] 在一些数据库系统里,包括老版本的 PostgreSQL, DISTINCT 的实现自动对行进行排序,因此 ORDER BY 是多余的。但是这一点并不是 SQL 标准的要求,并且目前的 PostgreSQL 并不保证 DISTINCT 导致数据行被排序。

TOP

2.6. 在表之间连接
到目前为止,我们的查询一次只访问了一个表。 查询可以一次访问多个表,或者用某种方式访问一个表,而同时处理该表的多个行。 一个同时访问同一个或者不同表的多个行的查询叫连接(join)查询。 举例来说,比如你想列出所有天气记录以及这些记录相关的城市。 要实现这个目标,我们需要拿 weather表每行的city 字段和cities表所有行的name字段进行比较, 并选取那些这些数值相匹配的行。

注意: 这里只是一个概念上的模型。该连接通常以比实际比较每个可能的行配对更高效的方式执行, 但这些是用户看不到的。

这个任务可以用下面的查询来实现:

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;

TOP

练习:. 看看省略 WHERE 子句的语义是什么。

因为这些字段的名字都不一样,所以分析器自动找出它们属于哪个表, 但是在连接查询里使用字段全称是很好的风格:

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 表里面的行。 如果我们没有找到匹配的行,那么我们需要一些"空值"代替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)。

TOP

练习:. 还有右连接和全连接。试着找出来它们能干什么。

我们也可以把一个表和自己连接起来。这叫做自连接。 比如,假设我们想找出那些在其它天气记录的温度范围之外的天气记录。 这样我们就需要拿 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;你以后会经常碰到这样的缩写的.

TOP

2.7. 聚集函数
和大多数其它关系数据库产品一样, PostgreSQL 支持聚集函数。 一个聚集函数从多个输入行中计算出一个结果。 比如,我们有在一个行集合上计算 count(数目), sum(和),avg(均值), max(最大值)和min(最小值)的函数。

比如,我们可以用下面的语句找出所有记录中低温中的最高温度

SELECT max(temp_lo) FROM weather;
max
-----
  46
(1 row)
如果我们想知道该读数发生在哪个城市,我们可以用

SELECT city FROM weather WHERE temp_lo = max(temp_lo);     WRONG不过这个方法不能运转,因为聚集 max 不能用于 WHERE 子句中。 (存在这个限制是因为 WHERE 子句决定哪些行可以进入聚集阶段;因此它必需在聚集函数之前计算。) 不过,我们通常都可以用其它方法实现我们的目的;这里我们就可以使用子查询:

SELECT city FROM weather
    WHERE temp_lo = (SELECT max(temp_lo) FROM weather);
     city
---------------
San Francisco
(1 row)这样做是 OK 的,因为子查询是一次独立的计算,它独立于外层的查询计算出自己的聚集。

TOP

聚集同样也常用于 GROUP BY 子句。比如, 我们可以获取每个城市低温的最高值

SELECT city, max(temp_lo)
    FROM weather
    GROUP BY city;
     city      | max
---------------+-----
Hayward       |  37
San Francisco |  46
(2 rows)这样给我们每个城市一个输出。 每个聚集结果都是在匹配该城市的行上面计算的。 我们可以用 HAVING 过滤这些分组:

SELECT city, max(temp_lo)
    FROM weather
    GROUP BY city
    HAVING max(temp_lo) < 40;
  city   | max
---------+-----
Hayward |  37
(1 row)

TOP

这样就只给出那些 temp_lo 数值曾经有低于 40 度温度的城市。 最后,如果我们只关心那些名字以 "S" 开头的城市,我们可以用

SELECT city, max(temp_lo)
    FROM weather
    WHERE city LIKE 'S%'(1)
    GROUP BY city
    HAVING max(temp_lo) < 40;
(1)
LIKE 做模式匹配,在 Section 9.7 里有解释。

理解聚集和SQL的 WHERE 以及 HAVING 子句之间的关系对我们非常重要。 WHERE 和 HAVING 的基本区别如下: WHERE 在分组和聚集计算之前选取输入行(因此,它控制哪些行进入聚集计算), 而 HAVING 在分组和聚集之后选取分组的行。 因此,WHERE 子句不能包含聚集函数; 因为试图用聚集函数判断那些行输入给聚集运算是没有意义的。 相反,HAVING 子句总是包含聚集函数。 (严格说来,你可以写不使用聚集的 HAVING 子句, 但这样做很少有用。同样的条件可以更有效地用于 WHERE 阶段。)

在前面的例子里,我们可以在 WHERE 里应用城市名称限制,因为它不需要聚集。 这样比在 HAVING 里增加限制更加高效,因为我们避免了为那些未通过 WHERE 检查的行进行分组和聚集计算。

TOP

2.8. 更新
你可以用 UPDATE 命令更新现有的行。 假设你发现所有 11 月 28 日的温度计数都低了两度,那么你就可以用下面的方式更新数据:

UPDATE weather
    SET temp_hi = temp_hi - 2,  temp_lo = temp_lo - 2
    WHERE date > '1994-11-28';
看看数据的新状态:

SELECT * FROM weather;

     city      | temp_lo | temp_hi | prcp |    date
---------------+---------+---------+------+------------
San Francisco |      46 |      50 | 0.25 | 1994-11-27
San Francisco |      41 |      55 |    0 | 1994-11-29
Hayward       |      35 |      52 |      | 1994-11-29
(3 rows)

TOP

2.9. 删除
数据行可以用 DELETE 命令从表中删除。 假设你对Hayward的天气不再感兴趣,那么你可以用下面的方法把那些行从表中删除:

DELETE FROM weather WHERE city = 'Hayward';所有属于Hayward的天气记录都将被删除。

SELECT * FROM weather;
     city      | temp_lo | temp_hi | prcp |    date
---------------+---------+---------+------+------------
San Francisco |      46 |      50 | 0.25 | 1994-11-27
San Francisco |      41 |      55 |    0 | 1994-11-29
(2 rows)
我们用下面形式的语句的时候一定要小心

DELETE FROM tablename;如果没有条件,DELETE 将从指定表中删除所有行,把它清空。做这些之前系统不会请求你确认!

TOP

Chapter 3. 高级特性
Table of Contents
3.1. 介绍
3.2. 视图
3.3. 外键
3.4. 事务
3.5. 继承
3.6. 结论
3.1. 介绍
在前面几章里,我们介绍了使用 SQL 存储和访问在 PostgreSQL 里的数据的基本方法。 我们现在将讨论一些 SQL 更高级的特性,这些特性可以简化管理和避免你的数据的丢失或损坏。 最后,我们将看看一些 PostgreSQL 的扩展。

本章将不时引用在 Chapter 2 里的例子, 并且对它们进行修改和提高,因此如果你已经看过那章会更好。 本章的一些例子也可以在教程目录里的 advanced.sql 文件里找到。 这个文件还包括一些要装载的例子数据,这些数据没有在这里介绍。 (请参考 Section 2.1 获取如何使用该文件的方法。)

TOP


感谢一直以来您对我们的支持!
当前时区 GMT+8, 现在时间是 2008-10-12 17:24 京ICP证060528 号

Designed By 17DST