打印

PostgreSQL 8.1 中文文档

3.2. 视图
回头看看在 Section 2.6 里的查询。 假设你的应用对天气记录和城市位置的组合列表特别感兴趣, 而你又不想每次键入这些查询。那么你可以在这个查询上创建一个视图, 它给这个查询一个名字,你可以像普通表那样引用它。

CREATE VIEW myview AS
    SELECT city, temp_lo, temp_hi, prcp, date, location
        FROM weather, cities
        WHERE city = name;

SELECT * FROM myview;
自由地运用视图是好的 SQL 数据库设计的一个关键要素。 视图允许我们把表结构的细节封装起来,这些表可能因你的应用的进化而变化, 而这些变化却可以躲在一个一致的接口后面。

视图几乎可以在一个真正的表可以使用的任何地方使用。 在其它视图上面再建造视图也并非罕见。

TOP

3.3. 外键
回忆一下 Chapter 2 里的 weather 和 cities 表。考虑一下下面的问题:你想确保没有人可以在 weather 表里插入一条在 cities 表里没有匹配记录的数据行。 这就叫维护你的表的参考完整性。 在简单的数据库系统里,实现(如果也叫实现)这个特性的方法 通常是先看看 cities 表里是否有匹配的记录, 然后插入或者拒绝新的 weather 记录。 这个方法有许多问题,而且非常不便,因此 PostgreSQL 可以为你做这些。

新的表声明看起来会象下面这样:

CREATE TABLE cities (
        city            varchar(80) primary key,
        location        point
);

CREATE TABLE weather (
        city            varchar(80) references cities(city),
        temp_lo         int,
        temp_hi         int,
        prcp            real,
        date            date
);
然后我们试图插入一条非法的记录:

INSERT INTO weather VALUES ('Berkeley', 45, 53, 0.0, '1994-11-28');
ERROR:  insert or update on table "weather" violates foreign key constraint "weather_city_fkey"
DETAIL:  Key (city)=(Berkeley) is not present in table "cities".
外键的行为可以为你的应用仔细调节。在这份教程里我们就不再多说了,而是请你参考Chapter 5获取更多的信息。 正确使用外键无疑将改进你的数据库应用,所以我们强烈建议你学习它们。

TOP

3.4. 事务
事务是所有数据库系统的一个基本概念。 一次事务的要点就是它把多个步骤捆绑成了一个单一的,不成功则成仁的操作。 其它并发的事务是看不到在这些步骤之间的中间状态的,并且如果发生了一些问题, 导致该事务无法完成,那么所有这些步骤都完全不会影响数据库。

比如,假设一个银行的数据库包含各种客户帐户的余额,以及每个分行的总余额。 假设我们要记录一次从 Alice 的帐户到 Bob 的帐户的金额为 $100.00 的支付动作。那么,完成这个任务的简单到极点的 SQL 命令象下面这样

UPDATE accounts SET balance = balance - 100.00
    WHERE name = 'Alice';
UPDATE branches SET balance = balance - 100.00
    WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Alice');
UPDATE accounts SET balance = balance + 100.00
    WHERE name = 'Bob';
UPDATE branches SET balance = balance + 100.00
    WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Bob');
这些命令的细节在这儿并不重要;重要的是这里牵涉到了好几个独立的更新来完成这个相当简单的操作。 我们的银行官员会希望要么所有这些更新都生效,要么全部不起作用。 我们当然不希望一次系统崩溃就导致 Bob 收到 100 块不是 Alice 支付的钱, 也不希望 Alice 老是不花钱从 Bob 那里拿到物品。我们需要保证:如果在操作的过程中出了差错, 那么所有这些步骤都不会发生效果。把这些更新组合成一个事务就给予我们这样的保证。 事务被认为是原子的:从其它事务的角度来看,它要么是全部发生,要么完全不发生。

我们还需要保证:一旦一个事务完成并且得到数据库系统的认可, 那么它必须被真正永久地存储,并且不会在随后的崩溃中消失。 比如,如果我们记录到了一个 Bob 撤单的动作, 那么我们不希望仅仅在他走出银行大门之后的一次崩溃就会导致对他的帐户的扣减动作消失。 一个事务型数据库保证一个事务所做的所有更新在事务发出完成响应之前都记录到永久的存储中(也就是磁盘)。

事务型数据库的另外一个重要的性质和原子更新的概念关系密切: 当多个事务并发地运行的时候,那么每个事务都不应看到其它事务所做的未完成的变化。 比如,如果一个事务正忙着计算所有分行的余额总和, 那么它不应该包括来自 Alice 的分行的扣帐和来自 Bob 分行的入帐,反之亦然。 所以事务必须是黑白分明的,不仅仅体现在它们在数据库上产生的永久影响出发,而且体现在它们运转时的自身的可视性上。 一个打开的事务做的更新在它完成之前是其它事务无法看到的,而到提交的时候所有更新同时可见。

在 PostgreSQL 里,一个事务是通过把 SQL 命令用 BEGIN 和 COMMIT 命令包围实现的。 因此我们的银行事务实际上看起来象下面这样

BEGIN;
UPDATE accounts SET balance = balance - 100.00
    WHERE name = 'Alice';
-- 等等
COMMIT;
如果在该事务的过程中,我们决定不做提交(可能是我们刚发现 Alice 的余额是负数), 那么我们可以发出 ROLLBACK 命令而不是 COMMIT 命令,那么到目前为止我们的所有更新都会被取消。

PostgreSQL 实际上把每个 SQL 语句当做在一个事务中执行的来看待。 如果你没有发出 BEGIN 命令,那么每个独立的语句都有一个隐含的 BEGIN 和(如果成功的话) COMMIT 语句包围在周围。 一组包围在 BEGIN 和 COMMIT 语句中间的语句有时候被称做事务块。

注意: 一些客户库自动发出 BEGIN 和 COMMIT, 因此你可能不需要特意请求就可以获取事务块的效果。查看你使用的接口的文档。

TOP

我们可以通过使用 savepoints 的方法,在一个事务里更加精细地控制其中的语句。 保存点允许你有选择性地抛弃事务中的某些部分,而提交其它剩下的。 在用 SAVEPOINT 定义了一个保存点后,如果需要,你可以使用 ROLLBACK TO 回滚到该保存点。 则该事务在定义保存点到回滚到它之间的所有数据库更改都被抛弃,但是在保存点之前的修改将被保留。

在回滚到一个保存点之后,这个保存点仍然保存着其定义,所以你可以回滚到这个位置好几次。 当然,如果你确信你不需要再次回滚到一个保存点,那么你可以释放它,这样系统可以释放一些资源。 要记住:释放或者回滚到一个保存点都会自动释放在其后定义的所有保存点。

所有这些都发生在一个事务块内部,所以所有这些都不可能被其它事务会话看到。 当且仅当你提交了这个事务块,这些提交了的动作才能以一个单元的方式被其它会话看到, 而回滚的动作完全不会再被看到。

还记得我们的银行数据库吗?假设我们从 Alice 的帐户上消费 $100.00, 然后给 Bob 的帐户进行贷记加款,稍后我们发现我们应该给 Wally 的账号贷记加款。 那么我们可以像下面这样的保存点来做:

BEGIN;
UPDATE accounts SET balance = balance - 100.00
    WHERE name = 'Alice';
SAVEPOINT my_savepoint;
UPDATE accounts SET balance = balance + 100.00
    WHERE name = 'Bob';
-- 呀!加错钱了,应该用 Wally 的账号
ROLLBACK TO my_savepoint;
UPDATE accounts SET balance = balance + 100.00
    WHERE name = 'Wally';
COMMIT;
这个例子当然是实在太简单了,但是通过使用保存点,我们可以对事务块有大量的控制。 并且,ROLLBACK TO 是除了事务全部回滚,重新来过之外的唯一可用的, 用于重新控制一个因错误而被系统置于退出状态下的事务的方法。

TOP

3.5. 继承
继承是面向对象的数据库的概念。它开启了数据库设计新的有趣的可能性大门。

让我们创建两个表:一个表 cities 和一个表 capitals。自然,首府(capital)也是城市(cities), 因此在列出所有城市时你想要某种方法隐含地显示首府。 如果你已经很高明了,那么你可能会创造类似下面这样的模式:

CREATE TABLE capitals (
    name            text,
    population      real,
    altitude        int,    -- (单位是英尺)
    state           char(2)
);

CREATE TABLE non_capitals (
    name            text,
    population      real,
    altitude        int     -- (单位是英尺)
);

CREATE VIEW cities AS
    SELECT name, population, altitude FROM capitals
        UNION
    SELECT name, population, altitude FROM non_capitals;如果只是查询,那么这个方法运转得很好,比如如果你需要更新某几行, 那这个方法就很难看了。

一种更好的方法是:

CREATE TABLE cities (
    name            text,
    population      real,
    altitude        int     -- (单位是英尺)
);

CREATE TABLE capitals (
    state           char(2)
) INHERITS (cities);
在这个例子里,capitals 的一行继承所有来自它的父表, cities 的所有字段(name, population,和 altitude)。 字段 name 的类型是 text, 是 PostgreSQL 用于变长字符串的固有类型。 州首府有一个额外的字段,州,显示所处的州。在 PostgreSQL 里,一个表可以从零个或者更多其它表中继承过来。

TOP

比如,下面的查询找出所有海拔超过 500 英尺的城市的名字, 包括州首府:

SELECT name, altitude
    FROM cities
    WHERE altitude > 500;它返回:

   name    | altitude
-----------+----------
Las Vegas |     2174
Mariposa  |     1953
Madison   |      845
(3 rows)
另外一方面,下面的查询找出所有不是州首府并且位于海拔大于或等于 500 英尺的城市:

SELECT name, altitude
    FROM ONLY cities
    WHERE altitude > 500;
   name    | altitude
-----------+----------
Las Vegas |     2174
Mariposa  |     1953
(2 rows)
这里的 cities 前面的 ONLY 指示系统只对 cities 表运行查询,而不包括继承级别中低于 cities 的表。 许多我们已经讨论过的命令 — SELECT, UPDATE 和 DELETE — 支持这个 ONLY 表示法。

注意: 尽管继承经常是有用的,但是它还没有集成唯一约束或者外键,因此制约了其实用性。 参阅 Section 5.8 获取更多细节。

TOP

3.6. 结论
PostgreSQL 有许多这份教程里没有谈到的特性, 因为这份教程主要是面向新 SQL 用户的。这些特性在本书剩余部分将有更详细的介绍。

如果你觉得自己需要更多介绍性材料,请访问 PostgreSQL网站 获取更多资源的联接。

TOP

II. SQL 语言
这一部分描述 PostgreSQL 里面 SQL 语言的使用。我们从描述 SQL 的一般语法开始, 然后解释如何创建保存数据的结构,如何填充数据库,以及如何查询数据库。 中间部分列出了用户可以在 SQL 命令中可用的数据类型和函数。 剩下的部分讨论那些对调节数据库,优化其性能很重要的几个方面。

这一部分的信息是这样安排的:新手可以从头读到尾, 便可以获取有关主题的完整了解,而不需要向前引用太多的次数。 里面的章节是设计成自包含的,这样高级用户就可以选择独立的章节来阅读。 这部分的信息是按照主题单元以叙述的方式组织的。 如果你需要了解特定命令的完整描述,那么应该看看 Part VI。

本书的读者应该知道如何与一个 PostgreSQL 数据库连接并发出 SQL 命令。 我们建议那些不熟悉这些方面的读者首先阅读 Part I。 通常 SQL 命令是用 PostgreSQL 交互终端 psql 输入的,但其它有类似功能的程序也可以使用。

Table of Contents
4. SQL 语法
4.1. 词法结构
4.2. 值表达式
5. 数据定义
5.1. 表的基本概念
5.2. 缺省值
5.3. 约束
5.4. 系统字段
5.5. 修改表
5.6. 权限
5.7. 模式
5.8. 继承
5.9. 分区
5.10. 其它数据库对象
5.11. 依赖性追踪
6. 数据操作
6.1. 插入数据
6.2. 更新数据
6.3. 删除数据
7. 查询
7.1. 概述
7.2. 表表达式
7.3. 选择列表
7.4. 组合查询
7.5. 行排序
7.6. LIMIT 和 OFFSET
8. 数据类型
8.1. 数值类型
8.2. 货币类型
8.3. 字符类型
8.4. 二进制数据类型
8.5. 日期/时间类型
8.6. 布尔类型
8.7. 几何类型
8.8. 网络地址数据类型
8.9. 位串类型
8.10. 数组
8.11. 复合类型
8.12. 对象标识符类型
8.13. 伪类型
9. 函数和操作符
9.1. 逻辑操作符
9.2. 比较操作符
9.3. 数学函数和操作符
9.4. 字符串函数和操作符
9.5. 二进制字串函数和操作符
9.6. 位串函数和操作符
9.7. 模式匹配
9.8. 数据类型格式化函数
9.9. 时间/日期函数和操作符
9.10. 几何函数和操作符
9.11. 网络地址类型函数和操作符
9.12. 序列操作函数
9.13. 条件表达式
9.14. 数组函数和操作符
9.15. 聚集函数
9.16. 子查询表达式
9.17. 行和数组比较
9.18. 返回集合的函数
9.19. 系统信息函数
9.20. 系统管理函数
10. 类型转换
10.1. 概述
10.2. 操作符
10.3. 函数
10.4. 值存储
10.5. UNION,CASE 和相关构造
11. 索引
11.1. 介绍
11.2. 索引类型
11.3. 多字段索引
11.4. 组合多个索引
11.5. 唯一索引
11.6. 表达式上的索引
11.7. 部分索引
11.8. 操作符表
11.9. 检查索引的使用
12. 并发控制
12.1. 介绍
12.2. 事务隔离
12.3. 明确锁定
12.4. 应用层的数据完整性检查
12.5. 锁和索引
13. 性能提升技巧
13.1. 使用 EXPLAIN
13.2. 规划器使用的统计信息
13.3. 用明确的 JOIN (连接)控制规划器
13.4. 向数据库中添加记录

TOP

Chapter 4. SQL 语法
Table of Contents
4.1. 词法结构
4.1.1. 标识符和关键字
4.1.2. 常量
4.1.3. 操作符
4.1.4. 特殊字符
4.1.5. 注释
4.1.6. 词法优先级
4.2. 值表达式
4.2.1. 字段引用
4.2.2. 位置参数
4.2.3. 下标
4.2.4. 字段选择
4.2.5. 操作符调用
4.2.6. 函数调用
4.2.7. 聚集表达式
4.2.8. 类型转换
4.2.9. 标量子查询
4.2.10. 数组构造器
4.2.11. 行构造
4.2.12. 表达式计算规则
本章描述 SQL 的语法。 这些内容是理解随后各章的基础,那些章里面将详细介绍 SQL 命令如何用于定义和修改数据。

我们也建议那些已经很熟悉 SQL 的用户仔细阅读本章,因为有一些规则和概念在 SQL 数据库之间实现得并不一致,或者是有些东西是 PostgreSQL 特有的。

4.1. 词法结构
SQL 输入由一系列命令组成。 一条命令是由一系列记号构成, 用一个分号(";")结尾。 输入流的终止也结束一条命令。哪些记号是合法的取决于特定命令的语法。

记号可以是一个关键字, 一个标识符,一个 引号包围的标识符, 一个文本(或常量),或者是特殊的字符符号。 记号通常由空白分隔(空格,tab,换行符),但如果不存在混淆的时候也可以不用 (通常只是一个特殊字符与一些其它记号类型相联的时候)。

另外,在 SQL 输入里可以有注释。 它们不是记号,它们实际上等效于空白。

比如,下列命令是(语法上)合法的 SQL 输入:

SELECT * FROM MY_TABLE;
UPDATE MY_TABLE SET A = 5;
INSERT INTO MY_TABLE VALUES (3, 'hi there');这里是三条命令的序列,每条一行(尽管并不要求这么做; 多条命令可以在一行里,并且命令可以合理地分裂成多个行)。

如果从哪些记号标识命令,哪些是操作数或参数的角度考虑, SQL 语法并不是非常一致。通常头几个记号是命令名字, 因此上面的例子我们通常可以说是一个"SELECT", 一个"UPDATE",和一个"INSERT"命令。 不过, UPDATE 命令总是要求一个 SET 在某个位置出现,并且这个变体的 INSERT 还要求有一个 VALUES 才完整。每条命令的准确语法规则都在 Part VI 里描写。

TOP

4.1.1. 标识符和关键字
象上面的例子里的 SELECT,UPDATE, 或 VALUES 这样的记号都是关键字的例子, 也就是那些在 SQL 语言里有固定含义的单词。 记号 MY_TABLE 和 A 是标识符的例子。 根据使用它们的命令的不同,它们标识表,字段,或者其它数据库对象的名字。 因此,有时候只是简单地叫它们"名字"。 关键字和标识符有着同样的词法结构,意思是我们在没有认识这种语言之前是无法区分一个记号是标识符还是名字。 你可以在 Appendix C 里找到一个关键字的完整列表。

SQL 标识符和关键字必须以一个字母开头 (a-z 以及带可区别标记的字母以及非拉丁字母 )或下划线开头 (_)开头。标识符和关键字里随后的字符可以是字母,数字(0-9), 或者下划线,但 SQL 标准不会定义包含数字或者以下划线开头或结尾的关键字。

系统使用不超过 NAMEDATALEN-1 个字符作为标识符; 你可以在命令中写更长的名字,但它们会被截断。缺省时, NAMEDATALEN 是 64,因此标识符最大长度是 63 如果觉得这个限制有问题,那么你可以在 src/include/postgres_ext.h 里修改 NAMEDATALEN 来改变它。

标识符和关键字名字都是大小写无关的。因此

UPDATE MY_TABLE SET A = 5;也可以等效地写成

uPDaTE my_TabLE SeT a = 5;一种好习惯是把关键字写成大写,而名字等用小写。

UPDATE my_table SET a = 5;
还有第二种标识符:分隔标识符 或引号包围的标识符。 它是通过在双引号(" ) 里包围任意字符序列形成的。 分隔标识符总是一个标识符,而不是关键字。因此,你可以用 "SELECT" 表示一个字段名字或者名字叫 "SELECT" 的表,而一个没有引号的 SELECT 将被当做一条命令的一部分,因此如果把它当做一个表的名字或者字段名字用的话就会产生一个分析错误。 上面的例子可以用引起的标识符这么写:

UPDATE "my_table" SET "a" = 5;
引号包围的标识符可以包含除引号本身以外的任何其它字符。 要包含一个双引号,我们可以写两个双引号。 这样我们就可以构造那些原本是不允许的表或者字段名字, 比如那些包含空白或与号的名字。但长度限制依旧。

把一个标识符用引号包围的起来同时也令它大小写相关,而没有引号包围起来的名字总是转成小写。 比如,我们认为标识符 FOO,foo 和 "foo" 是一样的 PostgreSQL名字, 但 "Foo" 和 "FOO" 与上面三个以及它们之间都是不同的。 (PostgreSQL 里对未加引号的名子总是转换成小写, 这和 SQL 是不兼容的,SQL 里要求未用引号包围起来的名字总是转成大写。 因此 foo 等于 "FOO"。 如果你想写可移植的程序,那么我们建议你要么就总是引号包围的某个名字,要么就坚决不引。)

TOP


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

Designed By 17DST