============= 值表达式 ============= .. container:: sect1 :name: SQL-EXPRESSIONS .. container:: titlepage .. container:: .. container:: .. rubric:: 值表达式 :name: 值表达式 :class: title 值表达式被用于各种各样的环境中,例如在\ ``SELECT``\ 命令的目标列表中、作为\ ``INSERT``\ 或\ ``UPDATE``\ 中的新列值或者若干命令中的搜索条件。为了区别于一个表表达式(是一个表)的结果,一个值表达式的结果有时候被称为一个\ *标量*\ 。值表达式因此也被称为\ *标量表达式*\ (或者甚至简称为\ *表达式*\ )。表达式语法允许使用算数、逻辑、集合和其他操作从原始部分计算值。 一个值表达式是下列之一: .. container:: itemizedlist - 一个常量或文字值 - 一个列引用 - 在一个函数定义体或预备语句中的一个位置参数引用 - 一个下标表达式 - 一个域选择表达式 - 一个操作符调用 - 一个函数调用 - 一个聚集表达式 - 一个窗口函数调用 - 一个类型转换 - 一个排序规则表达式 - 一个标量子查询 - 一个数组构造器 - 一个行构造器 - 另一个在圆括号(用来分组子表达式以及重载优先级)中的值表达式 在这个列表之外,还有一些结构可以被分类为一个表达式,但是它们不遵循任何一般语法规则。这些通常具有一个函数或操作符的语义并且在\ `函数和操作符 `__\ 中的合适位置解释。一个例子是\ ``IS NULL``\ 子句。 我们已经在\ `词法结构 `__\ 中讨论过常量。下面的小节会讨论剩下的选项。 .. container:: sect2 :name: SQL-EXPRESSIONS-COLUMN-REFS .. container:: titlepage .. container:: .. container:: .. rubric:: 列引用 :name: 列引用 :class: title 一个列可以以下面的形式被引用: .. code:: synopsis correlation.columnname ``correlation``\ 是一个表(有可能以一个模式名限定)的名字,或者是在\ ``FROM``\ 子句中为一个表定义的别名。如果列名在当前索引所使用的表中都是唯一的,关联名称和分隔用的句点可以被忽略(另见\ `数据查询 `__\ )。 .. container:: sect2 :name: SQL-EXPRESSIONS-PARAMETERS-POSITIONAL .. container:: titlepage .. container:: .. container:: .. rubric:: 位置参数 :name: 位置参数 :class: title 一个位置参数引用被用来指示一个由 SQL 语句外部提供的值。参数被用于 SQL 函数定义和预备查询中。某些客户端库还支持独立于 SQL 命令字符串来指定数据值,在这种情况中参数被用来引用那些线外数据值。一个参数引用的形式是: .. code:: synopsis $number 例如,考虑一个函数\ ``dept``\ 的定义: .. code:: programlisting CREATE FUNCTION dept(text) RETURNS dept AS $$ SELECT * FROM dept WHERE name = $1 $$ LANGUAGE SQL; 这里\ ``$1``\ 引用函数被调用时第一个函数参数的值。 .. container:: sect2 :name: SQL-EXPRESSIONS-SUBSCRIPTS .. container:: titlepage .. container:: .. container:: .. rubric:: 下标 :name: 下标 :class: title 如果一个表达式得到了一个数组类型的值,那么可以抽取出该数组值的一个特定元素: .. code:: synopsis expression[subscript] 或者抽取出多个相邻元素(一个“数组切片”): .. code:: synopsis expression[lower_subscript:upper_subscript] (这里,方括号\ ``[ ]``\ 表示其字面意思)。每一个\ ``下标``\ 自身是一个表达式,它必须得到一个整数值。 通常,数组\ ``表达式``\ 必须被加上括号,但是当要被加下标的表达式只是一个列引用或位置参数时,括号可以被忽略。还有,当原始数组是多维时,多个下标可以被连接起来。例如: .. code:: programlisting mytable.arraycolumn[4] mytable.two_d_column[17][34] $1[10:42] (arrayfunction(a,b))[42] 最后一个例子中的圆括号是必需的。详见\ `数组 `__\ 。 .. container:: sect2 :name: FIELD-SELECTION .. container:: titlepage .. container:: .. container:: .. rubric:: 域选择 :name: 域选择 :class: title 如果一个表达式得到一个组合类型(行类型)的值,那么可以抽取该行的指定域 .. code:: synopsis expression.fieldname 通常行\ ``表达式``\ 必须被加上括号,但是当该表达式是仅从一个表引用或位置参数选择时,圆括号可以被忽略。例如: .. code:: programlisting mytable.mycolumn $1.somecolumn (rowfunction(a,b)).col3 (因此,一个被限定的列引用实际上只是域选择语法的一种特例)。一种重要的特例是从一个组合类型的表列中抽取一个域: .. code:: programlisting (compositecol).somefield (mytable.compositecol).somefield 这里需要圆括号来显示\ ``compositecol``\ 是一个列名而不是一个表名,在第二种情况中则是显示\ ``mytable``\ 是一个表名而不是一个模式名。 你可以通过书写\ ``.``\ 来请求一个组合值的所有域: .. code:: programlisting (compositecol).* 这种记法的行为根据上下文会有不同,详见\ `组合类型 `__\ 。 .. container:: sect2 :name: SQL-EXPRESSIONS-OPERATOR-CALLS .. container:: titlepage .. container:: .. container:: .. rubric:: 操作符调用 :name: 操作符调用 :class: title 对于一次操作符调用,有三种可能的语法: +----------------------------------------------------------------------+ | ``expression`` ``operator`` ``expression``\ (二元中缀操作符) | +----------------------------------------------------------------------+ | ``operator`` ``expression``\ (一元前缀操作符) | +----------------------------------------------------------------------+ | ``expression`` ``operator``\ (一元后缀操作符) | +----------------------------------------------------------------------+ 其中\ ``operator``\ 记号遵循\ `词法结构 `__\ 的语法规则,或者是关键词\ ``AND``\ 、\ ``OR``\ 和\ ``NOT``\ 之一,或者是一个如下形式的受限定操作符名: .. code:: synopsis OPERATOR(schema.operatorname) 哪个特定操作符存在以及它们是一元的还是二元的取决于由系统或用户定义的那些操作符。\ `函数与操作符 `__\ 描述了内建操作符。 .. container:: sect2 :name: SQL-EXPRESSIONS-FUNCTION-CALLS .. container:: titlepage .. container:: .. container:: .. rubric:: 函数调用 :name: 函数调用 :class: title 一个函数调用的语法是一个函数的名称(可能受限于一个模式名)后面跟上封闭于圆括号中的参数列表: .. code:: synopsis function_name ([expression [, expression ... ]] ) 例如,下面会计算 2 的平方根: .. code:: programlisting sqrt(2) 当在一个某些用户不信任其他用户的数据库中发出查询时,在编写函数调用时应遵守\ `函数 `__\ 中的安全防范措施。 内建函数的列表在\ `函数和操作符 `__\ 中。其他函数可以由用户增加。 参数可以有选择地被附加名称。详见\ `调用函数 `__\ 。 .. note:: .. rubric:: 注意 :name: 注意 :class: title 一个采用单一组合类型参数的函数可以被有选择地称为域选择语法,并且反过来域选择可以被写成函数的风格。也就是说,记号\ ``col(table)``\ 和\ ``table.col``\ 是可以互换的。这种行为是非 SQL 标准的但是在PostgreSQL中被提供,因为它允许函数的使用来模拟“计算域”。详见\ `组合类型 `__\ 。 .. container:: sect2 :name: SYNTAX-AGGREGATES .. container:: titlepage .. container:: .. container:: .. rubric:: 聚集表达式 :name: 聚集表达式 :class: title 一个\ *聚集表达式*\ 表示在由一个查询选择的行上应用一个聚集函数。一个聚集函数将多个输入减少到一个单一输出值,例如对输入的求和或平均。一个聚集表达式的语法是下列之一: .. code:: synopsis aggregate_name (expression [ , ... ] [ order_by_clause ] ) [ FILTER ( WHERE filter_clause ) ] aggregate_name (ALL expression [ , ... ] [ order_by_clause ] ) [ FILTER ( WHERE filter_clause ) ] aggregate_name (DISTINCT expression [ , ... ] [ order_by_clause ] ) [ FILTER ( WHERE filter_clause ) ] aggregate_name ( * ) [ FILTER ( WHERE filter_clause ) ] aggregate_name ( [ expression [ , ... ] ] ) WITHIN GROUP ( order_by_clause ) [ FILTER ( WHERE filter_clause ) ] 这里\ ``aggregate_name``\ 是一个之前定义的聚集(可能带有一个模式名限定),并且\ ``expression``\ 是任意自身不包含聚集表达式的值表达式或一个窗口函数调用。可选的\ ``order_by_clause``\ 和\ ``filter_clause``\ 描述如下。 第一种形式的聚集表达式为每一个输入行调用一次聚集。第二种形式和第一种相同,因为\ ``ALL``\ 是默认选项。第三种形式为输入行中表达式的每一个可区分值(或者对于多个表达式是值的可区分集合)调用一次聚集。第四种形式为每一个输入行调用一次聚集,因为没有特定的输入值被指定,它通常只对于\ ``count(*)``\ 聚集函数有用。最后一种形式被用于\ *有序集*\ 聚集函数,其描述如下。 大部分聚集函数忽略空输入,这样其中一个或多个表达式得到空值的行将被丢弃。除非另有说明,对于所有内建聚集都是这样。 例如,\ ``count(*)``\ 得到输入行的总数。\ ``count(f1)``\ 得到输入行中\ ``f1``\ 为非空的数量,因为\ ``count``\ 忽略空值。而\ ``count(distinct f1)``\ 得到\ ``f1``\ 的非空可区分值的数量。 一般地,交给聚集函数的输入行是未排序的。在很多情况中这没有关系,例如不管接收到什么样的输入,\ ``min``\ 总是产生相同的结果。但是,某些聚集函数(例如\ ``array_agg`` 和\ ``string_agg``\ )依据输入行的排序产生结果。当使用这类聚集时,可选的\ ``order_by_clause``\ 可以被用来指定想要的顺序。\ ``order_by_clause``\ 与查询级别的\ ``ORDER BY``\ 子句(如\ `第 7.5 节 `__\ 所述)具有相同的语法,除非它的表达式总是仅有表达式并且不能是输出列名称或编号。例如: .. code:: programlisting SELECT array_agg(a ORDER BY b DESC) FROM table; 在处理多参数聚集函数时,注意\ ``ORDER BY``\ 出现在所有聚集参数之后。例如,要这样写: .. code:: programlisting SELECT string_agg(a, ',' ORDER BY a) FROM table; 而不能这样写: .. code:: programlisting SELECT string_agg(a ORDER BY a, ',') FROM table; -- 不正确 后者在语法上是合法的,但是它表示用两个\ ``ORDER BY``\ 键来调用一个单一参数聚集函数(第二个是无用的,因为它是一个常量)。 如果在\ ``order_by_clause``\ 之外指定了\ ``DISTINCT``\ ,那么所有的\ ``ORDER BY``\ 表达式必须匹配聚集的常规参数。也就是说,你不能在\ ``DISTINCT``\ 列表没有包括的表达式上排序。 .. note:: .. rubric:: 注意 :name: 注意-1 :class: title 在一个聚集函数中指定\ ``DISTINCT``\ 以及\ ``ORDER BY``\ 的能力是一种PostgreSQL扩展。 按照到目前为止的描述,如果一般目的和统计性聚集中 排序是可选的,在要为它排序输入行时可以在该聚集的常规参数 列表中放置\ ``ORDER BY``\ 。有一个聚集函数的子集叫 做\ *有序集聚集*\ ,它\ *要求*\ 一个 ``order_by_clause``\ ,通常是因为 该聚集的计算只对其输入行的特定顺序有意义。有序集聚集的典 型例子包括排名和百分位计算。按照上文的最后一种语法,对于 一个有序集聚集, ``order_by_clause``\ 被写在 ``WITHIN GROUP (...)``\ 中。 ``order_by_clause``\ 中的表达式 会像普通聚集参数一样对每一个输入行计算一次,按照每个 ``order_by_clause``\ 的要求排序并 且交给该聚集函数作为输入参数(这和非 ``WITHIN GROUP`` ``order_by_clause``\ 的情况不同,在其中表达 式的结果不会被作为聚集函数的参数)。如果有在 ``WITHIN GROUP``\ 之前的参数表达式,会把它们称 为\ *直接参数*\ 以便与列在 ``order_by_clause``\ 中的 *聚集参数*\ 相区分。与普通聚集参数不同,针对 每次聚集调用只会计算一次直接参数,而不是为每一个输入行 计算一次。这意味着只有那些变量被\ ``GROUP BY`` 分组时,它们才能包含这些变量。这个限制同样适用于根本不在 一个聚集表达式内部的直接参数。直接参数通常被用于百分数 之类的东西,它们只有作为每次聚集计算用一次的单一值才有意 义。直接参数列表可以为空,在这种情况下,写成\ ``()`` 而不是\ ``(*)``\ (实际上 PostgreSQL接受两种拼写,但是只有第一 种符合 SQL 标准)。 有序集聚集的调用例子: .. code:: programlisting SELECT percentile_cont(0.5) WITHIN GROUP (ORDER BY income) FROM households; percentile_cont ----------------- 50489 这会从表\ ``households``\ 的 ``income``\ 列得到第 50 个百分位或者中位的值。 这里\ ``0.5``\ 是一个直接参数,对于百分位部分是一个 在不同行之间变化的值的情况它没有意义。 如果指定了\ ``FILTER``\ ,那么只有对\ ``filter_clause``\ 计算为真的输入行会被交给该聚集函数,其他行会被丢弃。例如: .. code:: programlisting SELECT count(*) AS unfiltered, count(*) FILTER (WHERE i < 5) AS filtered FROM generate_series(1,10) AS s(i); unfiltered | filtered ------------+---------- 10 | 4 (1 row) 预定义的聚集函数在\ `聚集函数 `__\ 中描述。其他聚集函数可以由用户增加。 一个聚集表达式只能出现在\ ``SELECT``\ 命令的结果列表或是\ ``HAVING``\ 子句中。在其他子句(如\ ``WHERE``\ )中禁止使用它,因为那些子句的计算在逻辑上是在聚集的结果被形成之前。 当一个聚集表达式出现在一个子查询中(见\ `值表达式 `__\ 和\ `子查询表达式 `__\ ),聚集通常在该子查询的行上被计算。但是如果该聚集的参数(以及\ ``filter_clause``\ ,如果有)只包含外层变量则会产生一个异常:该聚集则属于最近的那个外层,并且会在那个查询的行上被计算。该聚集表达式从整体上则是对其所出现于的子查询的一种外层引用,并且在那个子查询的任意一次计算中都作为一个常量。只出现在结果列表或\ ``HAVING``\ 子句的限制适用于该聚集所属的查询层次。 .. container:: sect2 :name: SYNTAX-WINDOW-FUNCTIONS .. container:: titlepage .. container:: .. container:: .. rubric:: 窗口函数调用 :name: 窗口函数调用 :class: title 一个\ *窗口函数调用*\ 表示在一个查询选择的行的某个部分上应用一个聚集类的函数。和非窗口聚集函数调用不同,这不会被约束为将被选择的行分组为一个单一的输出行 — 在查询输出中每一个行仍保持独立。不过,窗口函数能够根据窗口函数调用的分组声明(\ ``PARTITION BY``\ 列表)访问属于当前行所在分组中的所有行。一个窗口函数调用的语法是下列之一: .. code:: synopsis function_name ([expression [, expression ... ]]) [ FILTER ( WHERE filter_clause ) ] OVER window_name function_name ([expression [, expression ... ]]) [ FILTER ( WHERE filter_clause ) ] OVER ( window_definition ) function_name ( * ) [ FILTER ( WHERE filter_clause ) ] OVER window_name function_name ( * ) [ FILTER ( WHERE filter_clause ) ] OVER ( window_definition ) 其中\ ``window_definition``\ 的语法是 .. code:: synopsis [ existing_window_name ] [ PARTITION BY expression [, ...] ] [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ] [ frame_clause ] 可选的\ ``frame_clause``\ 是下列之一 .. code:: synopsis { RANGE | ROWS | GROUPS } frame_start [ frame_exclusion ] { RANGE | ROWS | GROUPS } BETWEEN frame_start AND frame_end [ frame_exclusion ] 其中\ ``frame_start``\ 和\ ``frame_end``\ 可以是下面形式中的一种 .. code:: synopsis UNBOUNDED PRECEDING offset PRECEDING CURRENT ROW offset FOLLOWING UNBOUNDED FOLLOWING 而\ ``frame_exclusion``\ 可以是下列之一 .. code:: synopsis EXCLUDE CURRENT ROW EXCLUDE GROUP EXCLUDE TIES EXCLUDE NO OTHERS 这里,\ ``expression``\ 表示任何自身不含有窗口函数调用的值表达式。 ``window_name``\ 是对定义在查询的\ ``WINDOW``\ 子句中的一个命名窗口声明的引用。还可以使用在\ ``WINDOW``\ 子句中定义命名窗口的相同语法在圆括号内给定一个完整的\ ``window_definition``\ ,详见\ `SELECT `__\ 参考页。值得指出的是,\ ``OVER wname``\ 并不严格地等价于\ ``OVER (wname ...)``\ ,后者表示复制并修改窗口定义,并且在被引用窗口声明包括一个帧子句时会被拒绝。 ``PARTITION BY``\ 选项将查询的行分组成为\ *分区*\ ,窗口函数会独立地处理它们。\ ``PARTITION BY``\ 工作起来类似于一个查询级别的\ ``GROUP BY``\ 子句,不过它的表达式总是只是表达式并且不能是输出列的名称或编号。如果没有\ ``PARTITION BY``\ ,该查询产生的所有行被当作一个单一分区来处理。\ ``ORDER BY``\ 选项决定被窗口函数处理的一个分区中的行的顺序。它工作起来类似于一个查询级别的\ ``ORDER BY``\ 子句,但是同样不能使用输出列的名称或编号。如果没有\ ``ORDER BY``\ ,行将被以未指定的顺序被处理。 ``frame_clause``\ 指定构成\ *窗口帧*\ 的行集合,它是当前分区的一个子集,窗口函数将作用在该帧而不是整个分区。帧中的行集合会随着哪一行是当前行而变化。在\ ``RANGE``\ 、\ ``ROWS``\ 或者\ ``GROUPS``\ 模式中可以指定帧,在每一种情况下,帧的范围都是从\ ``frame_start``\ 到\ ``frame_end``\ 。如果\ ``frame_end``\ 被省略,则末尾默认为\ ``CURRENT ROW``\ 。 ``UNBOUNDED PRECEDING``\ 的一个\ ``frame_start``\ 表示该帧开始于分区的第一行,类似地\ ``UNBOUNDED FOLLOWING``\ 的一个\ ``frame_end``\ 表示该帧结束于分区的最后一行。 在\ ``RANGE``\ 或\ ``GROUPS``\ 模式中,\ ``CURRENT ROW``\ 的一个\ ``frame_start``\ 表示帧开始于当前行的第一个\ *平级*\ 行(被窗口的\ ``ORDER BY``\ 子句排序为与当前行等效的行),而\ ``CURRENT ROW``\ 的一个\ ``frame_end``\ 表示帧结束于当前行的最后一个平级行。在\ ``ROWS``\ 模式中,\ ``CURRENT ROW``\ 就表示当前行。 在\ ``offset`` ``PRECEDING``\ 以及\ ``offset`` ``FOLLOWING``\ 帧选项中,\ ``offset``\ 必须是一个不包含任何变量、聚集函数或者窗口函数的表达式。\ ``offset``\ 的含义取决于帧模式: .. container:: itemizedlist - 在\ ``ROWS``\ 模式中,\ ``offset``\ 必须得到一个非空、非负的整数,并且该选项表示帧开始于当前行之前或者之后指定数量的行。 - 在\ ``GROUPS``\ 模式中,\ ``offset``\ 也必须得到一个非空、非负的整数,并且该选项表示帧开始于当前行的平级组之前或者之后指定数量的\ *平级组*\ ,这里平级组是在\ ``ORDER BY``\ 顺序中等效的行集合(要使用\ ``GROUPS``\ 模式,在窗口定义中就必须有一个\ ``ORDER BY``\ 子句)。 - 在\ ``RANGE``\ 模式中,这些选项要求\ ``ORDER BY``\ 子句正好指定一列。\ ``offset``\ 指定当前行中那一列的值与它在该帧中前面或后面的行中的列值的最大差值。\ ``offset``\ 表达式的数据类型会随着排序列的数据类型而变化。对于数字的排序列,它通常是与排序列相同的类型,但对于日期时间排序列它是一个\ ``interval``\ 。例如,如果排序列是类型\ ``date``\ 或者\ ``timestamp``\ ,我们可以写\ ``RANGE BETWEEN '1 day' PRECEDING AND '10 days' FOLLOWING``\ 。\ ``offset``\ 仍然要求是非空且非负,不过“非负”的含义取决于它的数据类型。 在任何一种情况下,到帧末尾的距离都受限于到分区末尾的距离,因此对于离分区末尾比较近的行来说,帧可能会包含比较少的行。 注意在\ ``ROWS``\ 以及\ ``GROUPS``\ 模式中,\ ``0 PRECEDING``\ 和\ ``0 FOLLOWING``\ 与\ ``CURRENT ROW``\ 等效。通常在\ ``RANGE``\ 模式中,这个结论也成立(只要有一种合适的、与数据类型相关的“零”的含义)。 ``frame_exclusion``\ 选项允许当前行周围的行被排除在帧之外,即便根据帧的开始和结束选项应该把它们包括在帧中。\ ``EXCLUDE CURRENT ROW``\ 会把当前行排除在帧之外。\ ``EXCLUDE GROUP``\ 会把当前行以及它在顺序上的平级行都排除在帧之外。\ ``EXCLUDE TIES``\ 把当前行的任何平级行都从帧中排除,但不排除当前行本身。\ ``EXCLUDE NO OTHERS``\ 只是明确地指定不排除当前行或其平级行的这种默认行为。 默认的帧选项是\ ``RANGE UNBOUNDED PRECEDING``\ ,它和\ ``RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW``\ 相同。如果使用\ ``ORDER BY``\ ,这会把该帧设置为从分区开始一直到当前行的最后一个\ ``ORDER BY``\ 平级行的所有行。如果不使用\ ``ORDER BY``\ ,就意味着分区中所有的行都被包括在窗口帧中,因为所有行都成为了当前行的平级行。 限制是\ ``frame_start``\ 不能是\ ``UNBOUNDED FOLLOWING``\ 、\ ``frame_end``\ 不能是\ ``UNBOUNDED PRECEDING``\ ,并且在上述\ ``frame_start``\ 和\ ``frame_end``\ 选项的列表中\ ``frame_end``\ 选择不能早于\ ``frame_start``\ 选择出现 — 例如不允许\ ``RANGE BETWEEN CURRENT ROW AND offset`` PRECEDING,但允许\ ``ROWS BETWEEN 7 PRECEDING AND 8 PRECEDING``\ ,虽然它不会选择任何行。 如果指定了\ ``FILTER``\ ,那么只有对\ ``filter_clause``\ 计算为真的输入行会被交给该窗口函数,其他行会被丢弃。只有是聚集的窗口函数才接受\ ``FILTER`` 。 内建的窗口函数在\ `窗口函数 `__\ 中介绍。用户可以加入其他窗口函数。此外,任何内建的或者用户定义的通用聚集或者统计性聚集都可以被用作窗口函数(有序集和假想集聚集当前不能被用作窗口函数)。 使用\ ````\ 的语法被用来把参数较少的聚集函数当作窗口函数调用,例如\ ``count(*) OVER (PARTITION BY x ORDER BY y)``\ 。星号(\ ````\ )通常不被用于窗口相关的函数。窗口相关的函数不允许在函数参数列表中使用\ ``DISTINCT``\ 或\ ``ORDER BY``\ 。 只有在\ ``SELECT``\ 列表和查询的\ ``ORDER BY``\ 子句中才允许窗口函数调用。 .. container:: sect2 :name: SQL-SYNTAX-TYPE-CASTS .. container:: titlepage .. container:: .. container:: .. rubric:: 类型转换 :name: 类型转换 :class: title 一个类型造型指定从一种数据类型到另一种数据类型的转换。PostgreSQL接受两种等价的类型造型语法: .. code:: synopsis CAST ( expression AS type ) expression::type ``CAST``\ 语法遵从 SQL,而用\ ``::``\ 的语法是PostgreSQL的历史用法。 当一个造型被应用到一种未知类型的值表达式上时,它表示一种运行时类型转换。只有已经定义了一种合适的类型转换操作时,该造型才会成功。注意这和常量的造型(如\ `词法结构 `__\ 中所示)使用不同。应用于一个未修饰串文字的造型表示一种类型到一个文字常量值的初始赋值,并且因此它将对任意类型都成功(如果该串文字的内容对于该数据类型的输入语法是可接受的)。 如果一个值表达式必须产生的类型没有歧义(例如当它被指派给一个表列),通常可以省略显式类型造型,在这种情况下系统会自动应用一个类型造型。但是,只有对在系统目录中被标记为“OK to apply implicitly”的造型才会执行自动造型。其他造型必须使用显式造型语法调用。这种限制是为了防止出人意料的转换被无声无息地应用。 还可以用像函数的语法来指定一次类型造型: .. code:: synopsis typename ( expression ) 不过,这只对那些名字也作为函数名可用的类型有效。例如,\ ``double precision``\ 不能以这种方式使用,但是等效的\ ``float8``\ 可以。还有,如果名称\ ``interval``\ 、\ ``time``\ 和\ ``timestamp``\ 被用双引号引用,那么由于语法冲突的原因,它们只能以这种风格使用。因此,函数风格的造型语法的使用会导致不一致性并且应该尽可能被避免。 .. note:: .. rubric:: 注意 :name: 注意-2 :class: title 函数风格的语法事实上只是一次函数调用。当两种标准造型语法之一被用来做一次运行时转换时,它将在内部调用一个已注册的函数来执行该转换。简而言之,这些转换函数具有和它们的输出类型相同的名字,并且因此“函数风格的语法”无非是对底层转换函数的一次直接调用。显然,一个可移植的应用不应当依赖于它。详见\ `CREATE CAST `__\ 。 .. container:: sect2 :name: SQL-SYNTAX-COLLATE-EXPRS .. container:: titlepage .. container:: .. container:: .. rubric:: 排序规则表达式 :name: 排序规则表达式 :class: title ``COLLATE``\ 子句会重载一个表达式的排序规则。它被追加到它适用的表达式: .. code:: synopsis expr COLLATE collation 这里\ ``collation``\ 可能是一个受模式限定的标识符。\ ``COLLATE``\ 子句比操作符绑得更紧,需要时可以使用圆括号。 如果没有显式指定排序规则,数据库系统会从表达式所涉及的列中得到一个排序规则,如果该表达式没有涉及列,则会默认采用数据库的默认排序规则。 ``COLLATE``\ 子句的两种常见使用是重载\ ``ORDER BY``\ 子句中的排序顺序,例如: .. code:: programlisting SELECT a, b, c FROM tbl WHERE ... ORDER BY a COLLATE "C"; 以及重载具有区域敏感结果的函数或操作符调用的排序规则,例如: .. code:: programlisting SELECT * FROM tbl WHERE a > 'foo' COLLATE "C"; 注意在后一种情况中,\ ``COLLATE``\ 子句被附加到我们希望影响的操作符的一个输入参数上。\ ``COLLATE``\ 子句被附加到该操作符或函数调用的哪个参数上无关紧要,因为被操作符或函数应用的排序规则是考虑所有参数得来的,并且一个显式的\ ``COLLATE``\ 子句将重载所有其他参数的排序规则(不过,附加非匹配\ ``COLLATE``\ 子句到多于一个参数是一种错误。因此,这会给出和前一个例子相同的结果: .. code:: programlisting SELECT * FROM tbl WHERE a COLLATE "C" > 'foo'; 但是这是一个错误: .. code:: programlisting SELECT * FROM tbl WHERE (a > 'foo') COLLATE "C"; 因为它尝试把一个排序规则应用到\ ``>``\ 操作符的结果,而它的数据类型是非可排序数据类型\ ``boolean``\ 。 .. container:: sect2 :name: SQL-SYNTAX-SCALAR-SUBQUERIES .. container:: titlepage .. container:: .. container:: .. rubric:: 标量子查询 :name: 标量子查询 :class: title 一个标量子查询是一种圆括号内的普通\ ``SELECT``\ 查询,它刚好返回一行一列(关于书写查询可见\ `查询 `__\ )。\ ``SELECT``\ 查询被执行并且该单一返回值被使用在周围的值表达式中。将一个返回超过一行或一列的查询作为一个标量子查询使用是一种错误(但是如果在一次特定执行期间该子查询没有返回行则不是错误,该标量结果被当做为空)。该子查询可以从周围的查询中引用变量,这些变量在该子查询的任何一次计算中都将作为常量。对于其他涉及子查询的表达式还可见\ `子查询表达式 `__\ 。 例如,下列语句会寻找每个州中最大的城市人口: .. code:: programlisting SELECT name, (SELECT max(pop) FROM cities WHERE cities.state = states.name) FROM states; .. container:: sect2 :name: SQL-SYNTAX-ARRAY-CONSTRUCTORS .. container:: titlepage .. container:: .. container:: .. rubric:: 数组构造器 :name: 数组构造器 :class: title 一个数组构造器是一个能构建一个数组值并且将值用于它的成员元素的表达式。一个简单的数组构造器由关键词\ ``ARRAY``\ 、一个左方括号\ ``[``\ 、一个用于数组元素值的表达式列表(用逗号分隔)以及最后的一个右方括号\ ``]``\ 组成。例如: .. code:: programlisting SELECT ARRAY[1,2,3+4]; array --------- {1,2,7} (1 row) 默认情况下,数组元素类型是成员表达式的公共类型,使用和\ ``UNION``\ 或\ ``CASE``\ 结构(见\ `UNION、CASE和相关结构 `__\ )相同的规则决定。你可以通过显式将数组构造器造型为想要的类型来重载,例如: .. code:: programlisting SELECT ARRAY[1,2,22.7]::integer[]; array ---------- {1,2,23} (1 row) 这和把每一个表达式单独地造型为数组元素类型的效果相同。关于造型的更多信息请见\ `值表达式 `__\ 。 多维数组值可以通过嵌套数组构造器来构建。在内层的构造器中,关键词\ ``ARRAY``\ 可以被忽略。例如,这些语句产生相同的结果: .. code:: programlisting SELECT ARRAY[ARRAY[1,2], ARRAY[3,4]]; array --------------- {{1,2},{3,4}} (1 row) SELECT ARRAY[[1,2],[3,4]]; array --------------- {{1,2},{3,4}} (1 row) 因为多维数组必须是矩形的,处于同一层次的内层构造器必须产生相同维度的子数组。任何被应用于外层\ ``ARRAY``\ 构造器的造型会自动传播到所有的内层构造器。 多维数组构造器元素可以是任何得到一个正确种类数组的任何东西,而不仅仅是一个子-``ARRAY``\ 结构。例如: .. code:: programlisting CREATE TABLE arr(f1 int[], f2 int[]); INSERT INTO arr VALUES (ARRAY[[1,2],[3,4]], ARRAY[[5,6],[7,8]]); SELECT ARRAY[f1, f2, '{{9,10},{11,12}}'::int[]] FROM arr; array ------------------------------------------------ {{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}} (1 row) 你可以构造一个空数组,但是因为无法得到一个无类型的数组,你必须显式地把你的空数组造型成想要的类型。例如: .. code:: programlisting SELECT ARRAY[]::integer[]; array ------- {} (1 row) 也可以从一个子查询的结果构建一个数组。在这种形式中,数组构造器被写为关键词\ ``ARRAY``\ 后跟着一个加了圆括号(不是方括号)的子查询。例如: .. code:: programlisting SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%'); array ----------------------------------------------------------------------- {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31,2412,2413} (1 row) SELECT ARRAY(SELECT ARRAY[i, i*2] FROM generate_series(1,5) AS a(i)); array ---------------------------------- {{1,2},{2,4},{3,6},{4,8},{5,10}} (1 row) 子查询必须返回一个单一列。如果子查询的输出列是非数组类型, 结果的一维数组将为该子查询结果中的每一行有一个元素, 并且有一个与子查询的输出列匹配的元素类型。如果子查询的输出列 是一种数组类型,结果将是同类型的一个数组,但是要高一个维度。 在这种情况下,该子查询的所有行必须产生同样维度的数组,否则结果 就不会是矩形形式。 用\ ``ARRAY``\ 构建的一个数组值的下标总是从一开始。更多关于数组的信息,请见\ `数组 `__\ 。 .. container:: sect2 :name: SQL-SYNTAX-ROW-CONSTRUCTORS .. container:: titlepage .. container:: .. container:: .. rubric:: 行构造器 :name: 行构造器 :class: title 一个行构造器是能够构建一个行值(也称作一个组合类型)并用值作为其成员域的表达式。一个行构造器由关键词\ ``ROW``\ 、一个左圆括号、用于行的域值的零个或多个表达式(用逗号分隔)以及最后的一个右圆括号组成。例如: .. code:: programlisting SELECT ROW(1,2.5,'this is a test'); 当在列表中有超过一个表达式时,关键词\ ``ROW``\ 是可选的。 一个行构造器可以包括语法\ ``rowvalue``\ ``.``\ ,它将被扩展为该行值的元素的一个列表,就像在一个顶层\ ``SELECT``\ 列表(见\ `组合类型 `__\ )中使用\ ``.``\ 时发生的事情一样。例如,如果表\ ``t``\ 有列\ ``f1``\ 和\ ``f2``\ ,那么这些是相同的: .. code:: programlisting SELECT ROW(t.*, 42) FROM t; SELECT ROW(t.f1, t.f2, 42) FROM t; .. note:: .. rubric:: 注意 :name: 注意-3 :class: title 在PostgreSQL 8.2 以前,\ ``.``\ 语法不会在行构造器中被扩展,这样写\ ``ROW(t.*, 42)``\ 会创建一个有两个域的行,其第一个域是另一个行值。新的行为通常更有用。如果你需要嵌套行值的旧行为,写内层行值时不要用\ ``.``\ ,例如\ ``ROW(t, 42)``\ 。 默认情况下,由一个\ ``ROW``\ 表达式创建的值是一种匿名记录类型。如果必要,它可以被造型为一种命名的组合类型 — 或者是一个表的行类型,或者是一种用\ ``CREATE TYPE AS``\ 创建的组合类型。为了避免歧义,可能需要一个显式造型。例如: .. code:: programlisting CREATE TABLE mytable(f1 int, f2 float, f3 text); CREATE FUNCTION getf1(mytable) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL; -- 不需要造型因为只有一个 getf1() 存在 SELECT getf1(ROW(1,2.5,'this is a test')); getf1 ------- 1 (1 row) CREATE TYPE myrowtype AS (f1 int, f2 text, f3 numeric); CREATE FUNCTION getf1(myrowtype) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL; -- 现在我们需要一个造型来指示要调用哪个函数: SELECT getf1(ROW(1,2.5,'this is a test')); ERROR: function getf1(record) is not unique SELECT getf1(ROW(1,2.5,'this is a test')::mytable); getf1 ------- 1 (1 row) SELECT getf1(CAST(ROW(11,'this is a test',2.5) AS myrowtype)); getf1 ------- 11 (1 row) 行构造器可以被用来构建存储在一个组合类型表列中的组合值,或者被传递给一个接受组合参数的函数。还有,可以比较两个行值,或者用\ ``IS NULL``\ 或\ ``IS NOT NULL``\ 测试一个行,例如: .. code:: programlisting SELECT ROW(1,2.5,'this is a test') = ROW(1, 3, 'not the same'); SELECT ROW(table.*) IS NULL FROM table; -- detect all-null rows 详见\ `行和数组比较 `__\ 。如\ `子查询表达式 `__\ 中所讨论的,行构造器也可以被用来与子查询相连接。 .. container:: sect2 :name: SYNTAX-EXPRESS-EVAL .. container:: titlepage .. container:: .. container:: .. rubric:: 表达式计算规则 :name: 表达式计算规则 :class: title 子表达式的计算顺序没有被定义。特别地,一个操作符或函数的输入不必按照从左至右或其他任何固定顺序进行计算。 此外,如果一个表达式的结果可以通过只计算其一部分来决定,那么其他子表达式可能完全不需要被计算。例如,如果我们写: .. code:: programlisting SELECT true OR somefunc(); 那么\ ``somefunc()``\ 将(可能)完全不被调用。如果我们写成下面这样也是一样: .. code:: programlisting SELECT somefunc() OR true; 注意这和一些编程语言中布尔操作符从左至右的“短路”不同。 因此,在复杂表达式中使用带有副作用的函数是不明智的。在\ ``WHERE``\ 和\ ``HAVING``\ 子句中依赖副作用或计算顺序尤其危险,因为在建立一个执行计划时这些子句会被广泛地重新处理。这些子句中布尔表达式(\ ``AND``/``OR``/``NOT``\ 的组合)可能会以布尔代数定律所允许的任何方式被重组。 当有必要强制计算顺序时,可以使用一个\ ``CASE``\ 结构(见\ `条件表达式 `__\ )。例如,在一个\ ``WHERE``\ 子句中使用下面的方法尝试避免除零是不可靠的: .. code:: programlisting SELECT ... WHERE x > 0 AND y/x > 1.5; 但是这是安全的: .. code:: programlisting SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END; 一个以这种风格使用的\ ``CASE``\ 结构将使得优化尝试失败,因此只有必要时才这样做(在这个特别的例子中,最好通过写\ ``y > 1.5*x``\ 来回避这个问题)。 不过,\ ``CASE``\ 不是这类问题的万灵药。上述技术的一个限制是, 它无法阻止常量子表达式的提早计算,当查询被规划而不是被执行时,被标记成 ``IMMUTABLE``\ 的函数和操作符可以被计算。因此 .. code:: programlisting SELECT CASE WHEN x > 0 THEN x ELSE 1/0 END FROM tab; 很可能会导致一次除零失败,因为规划器尝试简化常量子表达式。即便是 表中的每一行都有\ ``x > 0``\ (这样运行时永远不会进入到 ``ELSE``\ 分支)也是这样。 虽然这个特别的例子可能看起来愚蠢,没有明显涉及常量的情况可能会发生 在函数内执行的查询中,因为因为函数参数的值和本地变量可以作为常量 被插入到查询中用于规划目的。例如,在PL/pgSQL函数 中,使用一个\ ``IF``-``THEN``-``ELSE``\ 语句来 保护一种有风险的计算比把它嵌在一个\ ``CASE``\ 表达式中要安全得多。 另一个同类型的限制是,一个\ ``CASE``\ 无法阻止其所包含的聚集表达式 的计算,因为在考虑\ ``SELECT``\ 列表或\ ``HAVING``\ 子句中的 其他表达式之前,会先计算聚集表达式。例如,下面的查询会导致一个除零错误, 虽然看起来好像已经这种情况加以了保护: .. code:: programlisting SELECT CASE WHEN min(employees) > 0 THEN avg(expenses / employees) END FROM departments; ``min()``\ 和\ ``avg()``\ 聚集会在所有输入行上并行地计算, 因此如果任何行有\ ``employees``\ 等于零,在有机会测试 ``min()``\ 的结果之前,就会发生除零错误。取而代之的是,可以使用 一个\ ``WHERE``\ 或\ ``FILTER``\ 子句来首先阻止有问题的输入行到达 一个聚集函数。