pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
值表达式被用于各种各样的环境中,例如在SELECT命令的目标列表中,作为INSERT或UPDATE中的新列值,或者作为若干命令中的搜索条件。为了与表表达式(其结果是一张表)区分开来,值表达式的结果有时被称为标量。因此,值表达式也称为标量表达式(甚至简称为表达式)。表达式语法允许使用算术、逻辑、集合以及其他操作,从基本部分计算出值。
一个值表达式是下列之一:
一个常量或字面值;见第 1.1.2 节。
一个列引用
在一个函数声明体中的一个位置参数引用
一个操作符调用
一个函数调用
一个聚合表达式
一个类型转换
一个标量子查询
另一个圆括号中的值表达式,用于对子表达式分组并覆盖优先级。
在这个列表之外,还有一些结构可以被分类为一个表达式,但是它们不遵循任何一般语法规则。这些通常具有一个函数或操作符的语义并且在第 6 章中的合适位置解释。一个示例是IS NULL子句。
我们已经在第 1.1.2 节中讨论过常量。下面的小节会讨论剩下的选项。
一个列可以以下面的形式被引用:
correlation.columnname
或者
correlation.columnname[subscript]
(这里,方括号[ ]表示其字面意思。)
correlation 是一个表的名字(可能带限定),或者是在 FROM 子句中为某个表定义的别名,或者是 关键词 NEW 或 OLD 之一。 (NEW 和 OLD 只能出现在重写规则中, 而其他关联名称可以用在任何 SQL 语句中。) 如果该列名在当前查询所用的所有表中都是唯一的,则关联名称和分隔用的句点都可以省略(另见第 4 章)。
如果 column 是一个数组类型,那么可选的 subscript 选择该数组中的一个或多个元素。如果没有提供下标,那么选中整个数组。(关于数组的更多信息见第 5.12 节。)
位置参数引用用来表示一个由 SQL 语句外部提供的参数。参数用于 SQL 函数定义和预备语句中。参数引用的形式是:
$number
例如,考虑一个函数dept的定义:
CREATE FUNCTION dept(text) RETURNS dept
AS 'SELECT * FROM dept WHERE name = $1'
LANGUAGE SQL;
这里$1引用函数被调用时第一个函数参数的值。
对于一次操作符调用,有三种可能的语法:
expression operator expression(二元中缀操作符) |
operator expression(一元前缀操作符) |
expression operator(一元后缀操作符) |
其中 operator 词元遵循 第 1.1.3 节 的语法规则,或者是关键词 AND, OR 和 NOT 之一,或者是一个模式限定的操作符名
OPERATOR(schema.operatorname)
具体存在哪些操作符以及它们是一元还是二元,取决于系统或用户定义了哪些操作符。第 6 章描述了内置操作符。
函数调用的语法是:函数名(可能带有模式名限定)后跟一组放在圆括号内的参数列表:
function([expression[,expression... ]] )
例如,下面会计算 2 的平方根:
sqrt(2)
内置函数的列表在第 6 章中。其他函数可以由用户增加。
一个聚合表达式表示将聚合函数应用于查询选中的各行。聚合函数将多个输入归约为单个输出值,例如输入的和或平均值。聚合表达式的语法可以是以下形式之一:
aggregate_name(expression)aggregate_name(ALLexpression)aggregate_name(DISTINCTexpression)aggregate_name( * )
其中,aggregate_name 是先前定义的聚合(可以是一个限定名),expression 是任何本身不包含聚合表达式的值表达式。
第一种形式的聚合表达式为所有使给定表达式产生非空值的输入行调用聚合。(实际上,是否忽略空值取决于聚合函数本身——但所有标准聚合都会忽略空值。)第二种形式和第一种相同,因为ALL是默认选项。第三种形式为输入行中表达式的所有非空可区分值调用聚合。最后一种形式为每一个输入行调用一次聚合而不管值是空还是非空;因为没有指定特定的输入值,它通常只对count()聚合函数有用。
例如,count(*)得到输入行的总数。count(f1)得到输入行中f1为非空的数量;而count(distinct f1)得到f1的非空可区分值的数量。
预定义的聚合函数在第 6.14 节中描述。其他聚合函数可以由用户增加。
一个类型转换指定从一种数据类型到另一种数据类型的转换。PostgreSQL接受两种等价的类型转换语法:
CAST (expressionAStype)expression::type
CAST语法遵从 SQL,而用::的语法是PostgreSQL的历史用法。
当类型转换被应用于一种已知类型的值表达式时,它表示一次运行时类型转换。只有在已经定义了合适的类型转换操作时,该类型转换才会成功。注意,这与常量上的类型转换(如第 1.1.2.4 节中所示)略有不同。应用于未修饰字符串字面量的类型转换,表示为一个字面常量值赋予初始类型,因此它对任意类型都能成功(前提是该字符串字面量的内容符合该数据类型的输入语法)。
如果一个值表达式必须产生的类型没有歧义(例如当它被赋给一个表列时),通常可以省略显式类型转换,在这种情况下系统会自动应用类型转换。但是,自动类型转换只会对那些在系统目录中被标记为“可以隐式应用”的类型转换执行。其他类型转换必须使用显式类型转换语法来调用。施加这一限制的目的是防止出人意料的转换被悄无声息地应用。
还可以用类似函数调用的语法来指定类型转换:
typename(expression)
不过,这只对那些名称本身也可作为函数名使用的类型有效。例如,double precision 不能用这种方式,但等效的 float8 可以。另外,由于语法冲突,名称 interval、time 和 timestamp 只有在使用双引号引用时才能采用这种写法。因此,函数风格的类型转换语法会带来不一致性,通常应尽量避免。 (函数风格的语法实际上只是一个函数调用。当两种标准转换语法之一被用于执行运行时转换时,它将在内部调用一个已注册的函数来执行转换。按照惯例,这些转换函数与它们的输出类型同名,但这不是可移植的应用程序应该依赖的东西。)
标量子查询是一个放在圆括号中的普通 SELECT 查询,它恰好返回一行一列(关于如何编写查询,见第 4 章)。该 SELECT 查询会被执行,其返回的单个值会用在外围值表达式中。把一个返回多于一行或多于一列的查询当作标量子查询来用是错误的。(但如果在某次具体执行中该子查询没有返回任何行,则不算错误;其标量结果会被视为空值。)该子查询可以引用外围查询中的变量,这些变量在该子查询的每一次求值期间都会作为常量。另见第 6.15 节。
例如,下列语句会寻找每个州中最大的城市人口:
SELECT name, (SELECT max(pop) FROM cities WHERE cities.state = states.name)
FROM states;
子表达式的计算顺序是未定义的。特别是,操作符或函数的输入不一定会按照从左到右或任何其他固定顺序计算。
此外,如果一个表达式的结果可以通过只计算其一部分来决定,那么其他子表达式可能完全不需要被计算。例如,如果我们写:
SELECT true OR somefunc();
那么somefunc()将(可能)完全不被调用。如果我们写成下面这样也是一样:
SELECT somefunc() OR true;
注意这和一些编程语言中布尔操作符从左至右的“短路”不同。
因此,在复杂表达式中使用带有副作用的函数是不明智的。在WHERE和HAVING子句中依赖副作用或计算顺序尤其危险,因为在建立一个执行计划时这些子句会被广泛地重新处理。这些子句中布尔表达式(AND/OR/NOT的组合)可能会以布尔代数定律所允许的任何方式被重组。
当有必要强制计算顺序时,可以使用一个CASE结构(见第 6.12 节)。例如,在一个WHERE子句中使用下面的方法尝试避免除零是不可靠的:
SELECT ... WHERE x <> 0 AND y/x > 1.5;
但是这是安全的:
SELECT ... WHERE CASE WHEN x <> 0 THEN y/x > 1.5 ELSE false END;
一个以这种风格使用的CASE结构将使得优化尝试失败,因此只有必要时才这样做。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。