7.3. 选择列表

如前面的小节说明的那样, 在 SELECT 命令里的表表达式构造了一个中介性的虚拟表, 方法可能有组合表,视图,删除行,分组等等。 这个表最后传递给选择列表处理。 选择列表判断中间表的哪个字段最终实际输出。

7.3.1. 选择列表项

最简单的选择列表类型是 *,它发出表表达式生成的所有字段。 否则,一个选择列表是一个逗号分隔的值表达式的列表, (和在Section 4.2 里定义的一样)。 比如,它可能是一个字段名字的列表:

SELECT a, b, c FROM ...

字段名字ab,和c要么是在 FROM子句里引用的表中字段的实际名字, 要么是象 Section 7.2.1.2 里解释的那样的别名。 在选择列表里的名字空间和在 WHERE 子句里的名字空间是一样的, 除非你使用了分组,这时候它和HAVING子句一样。

如果超过一个表有同样的字段名字,那么你还必须给出表名字,象

SELECT tbl1.a, tbl2.a, tbl1.b FROM ...

(又见 Section 7.2.2)。

如果将任意值表达式用于选择列表,那么它在概念上向返回的表中增加了一个新的虚拟字段。 值表达式为结果的每一行进行一次计算,计算之前用该行的数值代换任何表达式里引用的字段。 不过选择列表中的这个表达式并非一定要引用来自FROM子句中表表达式里面的字段, 比如,它也可以是任意常量算术表达式。

7.3.2. 字段标签

选择列表中的记录可以赋予名字,用于进一步的处理。 这里的"进一步处理"是一个可选的排序声明和客户端应用(比如,用于显示的字段头)。比如:

SELECT a AS value, b + c AS sum FROM ...

如果没有使用AS声明字段名字,那么系统赋予一个缺省值。对于简单的字段引用, 它是该字段的名字。对于函数调用,它是函数的名字。对于复杂表达式,系统会生成一个通用的名字。

注意: 输出字段的命名和在FROM子句里的命名是不一样的 (参阅 Section 7.2.1.2)。 这个管道实际上允许你对同一个列命名两次,但是在选择列表中选择的名字是要传递的名字。

7.3.3. DISTINCT

在处理完选择列表之后,生成的表可以删除重复行。 我们可以直接在 SELECT 后面写上 DISTINCT 关键字声明:

SELECT DISTINCT select_list ...

(如果不用 DISTINCT 你可以用 ALL 声明保留所有行的缺省行为。)

显然,如果两行里至少有一个列有不同的值,那么我们认为它是独立的。空值在这种考虑中认为是相同的。

另外,我们还可以用任意表达式来判断什么行可以认为是独立的:

SELECT DISTINCT ON (expression [, expression ...]) select_list ...

这里 expression 是任意值表达式, 它为所有行计算。如果一个行集合里所有行计算出的该表达式的值是一样的, 那么我们认为它们是重复的并且因此只有第一行保留在输出中。 请注意这里的一个集合的"第一行"是不可预料的, 除非你在足够多的字段上对该查询排了序,保证到达DISTINCT过滤器的行的顺序是唯一的。 (DISTINCT ON处理是发生在ORDER BY排序后面的。)

DISTINCT ON子句不是 SQL 标准的一部分, 有时候有人认为它是一个糟糕的风格,因为它的结果是不可判定的。 如果用有选择的GROUP BY和在FROM中的子查询,那么我们可以避免使用这个构造, 但是通常它是更方便的候选方法。