4.3. 常量

在**PostgreSQL**中有三种隐式类型常量 :字符串、位串和数字。常量也可以被指定显示类型,这可以使得它被更精确地展示以及更有效地处理。这些选择将会在后续小节中讨论。

4.3.1. 字符串常量

SQL中,一个字符串常量是一个由单引号(')包围的任意字符序列,例如'This is a string'。为了在一个字符串中包括一个单引号,可以写两个相连的单引号,例如'Dianne''s horse'。注意这和一个双引号(")同。

  • 两个只由空白及至少一个新行分隔的字符串常量会被连接在一起,并且将作为一个写在一起的字符串常量来对待。例如:
    SELECT 'foo'
    'bar';
    
  • 等同于:
    SELECT 'foobar';
    
  • 但是:
    SELECT 'foo'      'bar';
    

则不是合法的语法(这种有些奇怪的行为是SQL指定的,**PostgreSQL**遵循了该标准)。

4.3.2. C风格转义的字符串常量

**PostgreSQL**也接受"转义"字符串常量,这也是SQL标准的一个扩展。一个转义字符串常量可以通过在开单引号前面写一个字母E(大写或小写形式)来指定,例如E'foo'(当一个转义字符串常量跨行时,只在第一个开引号之前写E)。在一个转义字符串内部,一个反斜线字符(\)会开始一个 C 风格的反斜线转义 序列,在其中反斜线和后续字符的组合表示一个特殊的字节值(如表 4-1中所示)。

表 4-1. 反斜线转义序列

反斜线转义序列 解释
\b 退格
\f 换页
\n 换行
\r 回车
\t 制表符
\o,\oo,\ooo (o = 0 - 7) 八进制字节值
\xh, \xhh (h = 0 - 9, A - F) 十六进制字节值
\uxxxx, \Uxxxxxxxx (x = 0 - 9, A - F) 16 或 32-位十六进制 Unicode 字符值

跟随在一个反斜线后面的任何其他字符被当做其字面意思。因此,要包括一个反斜线字符,请写两个反斜线(\)。在一个转义字符串中包括一个单引号除了普通方法''之外,还可以写成'。

你要负责保证你创建的字节序列由服务器字符集编码中合法的字符组成,特别是在使用八进制或十六进制转义时。如果服务器编码为 UTF-8,那么应该使用 Unicode 转义或替代的 Unicode 转义语法。替代方案可能是手工写出 UTF-8 编码字节,这可能会非常麻烦。

只有当服务器编码是UTF8时,Unicode 转义语法才能完全工作。当使用其他服务器编码时,只有在 ASCII 范围(低于\u007F)内的代码点能够被指定。4 位和 8 位形式都能被用来指定 UTF-16 代理对,用来组成代码点超过 U+FFFF 的字符,不过 8 位形式的可用从技术上使得这种做法不再是必须的(当服务器编码为UTF8并使用代理对时,它们首先被结合到一个单一代码点,然后会被用 UTF-8 编码)。

小心:如果配置参数 standard_conforming_stringsoff,那么PostgreSQL对常规字符串常量和转义字符串常量中的反斜线转义都识别。不过,从PostgreSQL 9.1 开始,该参数的默认值为on,意味着只在转义字符串常量中识别反斜线转义。这种行为更兼容标准,但是可能打断依赖于历史行为(反斜线转义总是会被识别)的应用。作为一种变通,你可以设置该参数为off,但是最好迁移到符合新的行为。如果你需要使用一个反斜线转义来表示一个特殊字符,为该字符串常量写上一个E。在standard_conforming_strings之外,配置参数 escape_string_warningbackslash_quote 也决定了如何对待字符串常量中的反斜线。

4.3.3. 带有 Unicode 转义的字符串常量

PostgreSQL也支持另一种类型的字符串转义语法,它允许用代码点指定任意 Unicode 字符。一个 Unicode 转义字符串常量开始于U&(大写或小写形式的字母 U,后跟花号),后面紧跟着开引号,之间没有任何空白,例如U&'foo'(注意这产生了与操作符&的混淆。在操作符周围使用空白来避免这个问题)。在引号内,Unicode 字符可以通过写一个后跟 4 位十六进制代码点编号或者一个前面有加号的 6 位十六进制代码点编号的反斜线来指定。例如,字符串'data'可以被写为:U&'d\0061t\+000061'

  • 下面的例子用斯拉夫字母写出了俄语的单词"slon"(大象):U&'\0441\043B\043E\043D'
  • 如果想要一个不是反斜线的转义字符,可以在字符串之后使用UESCAPE子句来指定,例如:U&'d!0061t!+000061' UESCAPE '!'

转义字符可以是出一个十六进制位、加号、单引号、双引号或空白字符之外的任何单一字符。

只有当服务器编码是UTF8时,Unicode 转义语法才能完全工作。当使用其他服务器编码时,只有在 ASCII 范围(低于\u007F)内的代码点能够被指定。4 位和 8 位形式都能被用来指定 UTF-16 代理对,用来组成代码点超过 U+FFFF 的字符,不过 8 位形式的可用从技术上使得这种做法不再是必须的(当服务器编码为UTF8并使用代理对时,它们首先被结合到一个单一代码点,然后会被用 UTF-8 编码)。

还有,只有当配置参数 standard_conforming_strings 被打开时,用于字符串常量的 Unicode 转义语法才能工作。这是因为否则这种语法将迷惑客户端中肯地解析 SQL 语句,进而会导致 SQL 注入以及类似的安全性问题。如果这个参数被设置为关闭,这种语法将被拒绝并且报告一个错误消息。

要在一个字符串中包括一个表示其字面意思的转义字符,把它写两次。

4.3.4. 美元引用的字符串常量

虽然用于指定字符串常量的标准语法通常都很方便,但是当字符串中包含了很多单引号或反斜线时很难理解它,因为每一个都需要被双写。要在这种情形下允许可读性更好的查询,PostgreSQL提供了另一种被称为美元引用的方式来书写字符串常量。一个美元引用的字符串常量由一个美元符号($)、一个可选的另个或更多字符的"标签"、另一个美元符号、一个构成字符串内容的任意字符序列、一个美元符号、开始这个美元引用的相同标签和一个美元符号组成。例如,这里有两种不同的方法使用美元引用指定字符串"Dianne's horse":

$$Dianne's horse$$
$SomeTag$Dianne's horse$SomeTag$

注意在美元引用字符串中,单引号可以在不被转义的情况下使用。事实上,在一个美元引用字符串中不需要对字符进行转义:字符串内容总是按其字面意思写出。反斜线不是特殊的,并且美元符号也不是特殊的,除非它们是匹配开标签的一个序列的一部分。

可以通过在每一个嵌套级别上选择不同的标签来嵌套美元引用字符串常量。这最常被用在编写函数定义上。例如:

$function$
BEGIN
    RETURN ($1 ~ $q$[\t\r\n\v\\]$q$);
END;
$function$

这里,序列 $q$[\t\r\n\v\\]$q$ 表示一个美元引用的文字串 [\t\r\n\v\\],当该函数体被PostgreSQL执行时它将被识别。但是因为该序列不匹配外层的美元引用的定界符 $function$,它只是一些在外层字符串所关注的常量中的字符而已。

一个美元引用字符串的标签(如果有)遵循一个未被引用标识符的相同规则,除了它不能包含一个美元符号之外。标签是大小写敏感的,因此 $tag$String content$tag$ 是正确的,但是$TAG$String content$tag$不正确。

一个跟着一个关键词或标识符的美元引用字符串必须用空白与之分隔开,否则美元引用定界符可能会被作为前面标识符的一部分。

美元引用不是 SQL 标准的一部分,但是在书写复杂字符串文字方面,它常常是一种比兼容标准的单引号语法更方便的方法。当要表示的字符串常量位于其他常量中时它特别有用,这种情况常常在过程函数定义中出现。如果用单引号语法,上一个例子中的每个反斜线将必须被写成四个反斜线,这在解析原始字符串常量时会被缩减到两个反斜线,并且接着在函数执行期间重新解析内层字符串常量时变成一个。

4.3.5. 位串常量

位串常量看起来像常规字符串常量在开引号之前(中间无空白)加了一个B(大写或小写形式),例如B'1001'。位串常量中允许的字符只有0和1。

作为一种选择,位串常量可以用十六进制记号法指定,使用一个前导X(大写或小写形式),例如X'1FF'。这种记号法等价于一个用四个二进制位取代每个十六进制位的位串常量。

两种形式的位串常量可以以常规字符串常量相同的方式跨行继续。美元引用不能被用在位串常量中。

4.3.6. 数字常量

在这些一般形式中可以接受数字常量

digits
digits.[digits][e[+-]digits]
[digits].digits[e[+-]digits]
digitse[+-]digits

其中digits是一个或多个十进制数字(0 到 9)。如果使用了小数点,在小数点前面或后面必须至少有一个数字。如果存在一个指数标记(e),在其后必须跟着至少一个数字。在该常量中不能嵌入任何空白或其他字符。注意任何前导的加号或减号并不实际被考虑为常量的一部分,它是一个应用到该常量的操作符。这些是合法数字常量的例子:

42
3.5
4.
.001
5e2
1.925e-3

如果一个不包含小数点和指数的数字常量的值适合类型integer(32 位),它首先被假定为类型integer。否则如果它的值适合类型bigint(64 位),它被假定为类型bigint。再否则它会被取做类型numeric。包含小数点和/或指数的常量总是首先被假定为类型numeric。

一个数字常量初始指派的数据类型只是类型转换算法的一个开始点。在大部分情况中,常量将被根据上下文自动被强制到最合适的类型。必要时,你可以通过造型它来强制一个数字值被解释为一种指定数据类型。例如,你可以这样强制一个数字值被当做类型real(float4):

REAL '1.23'  -- string style
1.23::REAL   -- PostgreSQL (historical) style

这些实际上只是接下来要讨论的一般造型记号的特例。

4.3.7. 其他类型的常量

  • 一种任意类型的一个常量可以使用下列记号中的任意一种输入:
    type 'string'
    'string'::type
    CAST ( 'string' AS type )
    

字符串常量的文本被传递到名为type的类型的输入转换例程中。其结果是指定类型的一个常量。如果对该常量的类型没有歧义(例如,当它被直接指派给一个表列时),显式类型造型可以被忽略,在那种情况下它会被自动强制。

字符串常量可以使用常规 SQL 记号或美元引用书写。也可以使用一个类似函数的语法来指定一个类型强制:typename ( 'string' ) 但是并非所有类型名都可以用在这种方法中,详见 4.2. 标识符和关键词 第 9 节。

如第 4.2.9 节中讨论的,::、CAST()以及函数调用语法也可以被用来指定任意表达式的运行时类型转换。要避免语法歧义,type 'string'语法只能被用来指定简单文字常量的类型。type 'string'语法上的另一个限制是它无法对数组类型工作,指定一个数组常量的类型可使用::或CAST()。

CAST()语法符合 SQLtype 'string'语法是该标准的一般化:SQL 指定这种语法只用于一些数据类型,但是**PostgreSQL允许它用于所有类型。带有::的语法是PostgreSQL**的历史用法,就像函数调用语法一样。