来源:http://www.postgres.cn/docs/11/
4.1.1. 标识符和关键词
SQL标识符和关键词必须以一个字母(a
-z
,也可以是带变音符的字母和非拉丁字母)或一个下划线(_)开始。后续字符可以是字母、下划线(_
)、数字(0
-9
)或美元符号($
)。
系统中一个标识符的长度不能超过 NAMEDATALEN
-1 字节,在命令中可以写超过此长度的标识符,但是它们会被截断。默认情况下,NAMEDATALEN
的值为64,因此标识符的长度上限为63字节。如果这个限制有问题,可以在src/include/pg_config_manual.h
中修改 NAMEDATALEN
常量。
这里还有第二种形式的标识符:受限标识符或被引号修饰的标识符。它是由双引号("
)包围的一个任意字符序列。一个受限标识符总是一个标识符而不会是一个关键字。因此"select"
可以用于引用一个名为“select”的列或者表,而一个没有引号修饰的select
则会被当作一个关键词,从而在本应使用表或列名的地方引起解析错误。
4.1.2. 常量
在PostgreSQL中有三种隐式类型常量:字符串、位串和数字。
为了在一个字符串中包括一个单引号,可以写两个相连的单引号,例如'Dianne''s horse'
。注意这和一个双引号("
)不同。
在SQL中,一个字符串常量是一个由单引号('
)包围的任意字符序列,例如'This is a string'
。为了在一个字符串中包括一个单引号,可以写两个相连的单引号,例如'Dianne''s horse'
。注意这和一个双引号("
)不同。
两个只由空白及至少一个新行分隔的字符串常量会被连接在一起,并且将作为一个写在一起的字符串常量来对待。例如:
SELECT 'foo'
'bar';
等同于:SELECT 'foobar';
但是:SELECT 'foo' 'bar';
则不是合法的语法(这种有些奇怪的行为是SQL指定的,PostgreSQL遵循了该标准)。
位串常量看起来像常规字符串常量在开引号之前(中间无空白)加了一个B
(大写或小写形式),例如B'1001'
。位串常量中允许的字符只有0
和1
。
4.1.3. 操作符
一个操作符名是最多NAMEDATALEN
-1(默认为 63)的一个字符序列,其中的字符来自下面的列表:+ - * / < > = ~ ! @ # % ^ & | ` ?
4.1.4. 特殊字符
一些不是数字字母的字符有一种不同于作为操作符的特殊含义。这些字符的详细用法可以在描述相应语法元素的地方找到。这一节只是为了告知它们的存在以及总结这些字符的目的。
-
跟随在一个美元符号(
$
)后面的数字被用来表示在一个函数定义或一个预备语句中的位置参数。在其他上下文中该美元符号可以作为一个标识符或者一个美元引用字符串常量的一部分。 -
圆括号(
()
)具有它们通常的含义,用来分组表达式并且强制优先。在某些情况中,圆括号被要求作为一个特定 SQL 命令的固定语法的一部分。 -
方括号(
[]
)被用来选择一个数组中的元素。更多关于数组的信息见第 8.15 节。 -
逗号(
,
)被用在某些语法结构中来分割一个列表的元素。 -
分号(
;
)结束一个 SQL 命令。它不能出现在一个命令中间的任何位置,除了在一个字符串常量中或者一个被引用的标识符中。 -
冒号(
:
)被用来从数组中选择“切片”(见第 8.15 节)。在某些 SQL 的“方言”(例如嵌入式 SQL)中,冒号被用来作为变量名的前缀。 -
星号(
*
)被用在某些上下文中标记一个表的所有域或者组合值。当它被用作一个聚集函数的参数时,它还有一种特殊的含义,即该聚集不要求任何显式参数。 -
句点(
.
)被用在数字常量中,并且被用来分割模式、表和列名。
4.2.2. 位置参数
一个位置参数引用被用来指示一个由 SQL 语句外部提供的值。参数被用于 SQL 函数定义和预备查询中。某些客户端库还支持独立于 SQL 命令字符串来指定数据值,在这种情况中参数被用来引用那些线外数据值。一个参数引用的形式是:
$number
例如,考虑一个函数dept
的定义:
CREATE FUNCTION dept(text) RETURNS dept AS $$ SELECT * FROM dept WHERE name = $1 $$ LANGUAGE SQL;
这里$1
引用函数被调用时第一个函数参数的值。
4.2.7. 聚集表达式
一个聚集表达式表示在由一个查询选择的行上应用一个聚集函数。一个聚集函数将多个输入减少到一个单一输出值,例如对输入的求和或平均。
4.2.8. 窗口函数调用
一个窗口函数调用表示在一个查询选择的行的某个部分上应用一个聚集类的函数。和非窗口聚集函数调用不同,这不会被约束为将被选择的行分组为一个单一的输出行 — 在查询输出中每一个行仍保持独立。不过,窗口函数能够根据窗口函数调用的分组声明(PARTITION BY
列表)访问属于当前行所在分组中的所有行。
4.2.9. 类型转换
一个类型造型指定从一种数据类型到另一种数据类型的转换。PostgreSQL接受两种等价的类型造型语法:
CAST ( expression AS type ) expression::type
CAST
语法遵从 SQL,而用::
的语法是PostgreSQL的历史用法。
如果一个值表达式必须产生的类型没有歧义(例如当它被指派给一个表列),通常可以省略显式类型造型,在这种情况下系统会自动应用一个类型造型。
4.2.10. 排序规则表达式
COLLATE
子句会重载一个表达式的排序规则。它被追加到它适用的表达式:
expr COLLATE collation
这里collation
可能是一个受模式限定的标识符。COLLATE
子句比操作符绑得更紧,需要时可以使用圆括号。
4.2.11. 标量子查询
一个标量子查询是一种圆括号内的普通SELECT
查询,它刚好返回一行一列(关于书写查询可见第 7 章)。SELECT
查询被执行并且该单一返回值被使用在周围的值表达式中。将一个返回超过一行或一列的查询作为一个标量子查询使用是一种错误(但是如果在一次特定执行期间该子查询没有返回行则不是错误,该标量结果被当做为空)。该子查询可以从周围的查询中引用变量,这些变量在该子查询的任何一次计算中都将作为常量。对于其他涉及子查询的表达式还可见第 9.22 节。
例如,下列语句会寻找每个州中最大的城市人口:
SELECT name, (SELECT max(pop) FROM cities WHERE cities.state = states.name)
FROM states;
4.2.12. 数组构造器
一个数组构造器是一个能构建一个数组值并且将值用于它的成员元素的表达式。一个简单的数组构造器由关键词ARRAY
、一个左方括号[
、一个用于数组元素值的表达式列表(用逗号分隔)以及最后的一个右方括号]
组成。例如:
SELECT ARRAY[1,2,3+4]; array --------- {1,2,7} (1 row)
4.2.13. 行构造器
一个行构造器是能够构建一个行值(也称作一个组合类型)并用值作为其成员域的表达式。一个行构造器由关键词ROW
、一个左圆括号、用于行的域值的零个或多个表达式(用逗号分隔)以及最后的一个右圆括号组成。例如:
SELECT ROW(1,2.5,'this is a test');
当在列表中有超过一个表达式时,关键词ROW
是可选的。
4.2.14. 表达式计算规则
子表达式的计算顺序没有被定义。特别地,一个操作符或函数的输入不必按照从左至右或其他任何固定顺序进行计算。
此外,如果一个表达式的结果可以通过只计算其一部分来决定,那么其他子表达式可能完全不需要被计算。例如,如果我们写:
SELECT true OR somefunc();
那么somefunc()
将(可能)完全不被调用。如果我们写成下面这样也是一样:
SELECT somefunc() OR true;
注意这和一些编程语言中布尔操作符从左至右的“短路”不同。
4.3. 调用函数
PostgreSQL允许带有命名参数的函数被使用位置或命名记号法调用。命名记号法对于有大量参数的函数特别有用,因为它让参数和实际参数之间的关联更明显和可靠。在位置记号法中,书写一个函数调用时,其参数值要按照它们在函数声明中被定义的顺序书写。在命名记号法中,参数根据名称匹配函数参数,并且可以以任何顺序书写。对于每一种记法,还要考虑函数参数类型的效果,这些在第 10.3 节有介绍。
在任意一种记号法中,在函数声明中给出了默认值的参数根本不需要在调用中写出。但是这在命名记号法中特别有用,因为任何参数的组合都可以被忽略。而在位置记号法中参数只能从右往左忽略。
PostgreSQL也支持混合记号法,它组合了位置和命名记号法。在这种情况中,位置参数被首先写出并且命名参数出现在其后。
下列例子将展示所有三种记号法的用法:
CREATE FUNCTION concat_lower_or_upper(a text, b text, uppercase boolean DEFAULT false) RETURNS text AS $$ SELECT CASE WHEN $3 THEN UPPER($1 || ' ' || $2) ELSE LOWER($1 || ' ' || $2) END; $$ LANGUAGE SQL IMMUTABLE STRICT;
函数concat_lower_or_upper
有两个强制参数,a
和b
。此外,有一个可选的参数uppercase
,其默认值为false
。a
和b
输入将被串接,并且根据uppercase
参数被强制为大写或小写形式。这个函数的剩余细节对这里并不重要(详见第 38 章)。
4.3.2. 使用命名记号
在命名记号法中,每一个参数名都用=>
指定来把它与参数表达式分隔开。例如:
SELECT concat_lower_or_upper(a => 'Hello', b => 'World');
concat_lower_or_upper
-----------------------
hello world
(1 row)
再次,参数uppercase
被忽略,因此它被隐式地设置为false
。使用命名记号法的一个优点是参数可以用任何顺序指定,例如:
SELECT concat_lower_or_upper(a => 'Hello', b => 'World', uppercase => true);
concat_lower_or_upper
-----------------------
HELLO WORLD
(1 row)
SELECT concat_lower_or_upper(a => 'Hello', uppercase => true, b => 'World');
concat_lower_or_upper
-----------------------
HELLO WORLD
(1 row)
为了向后兼容性,基于 ":=" 的旧语法仍被支持:
SELECT concat_lower_or_upper(a := 'Hello', uppercase := true, b := 'World');
concat_lower_or_upper
-----------------------
HELLO WORLD
(1 row)