1.Base基础/3.Icon图标/操作/search备份
1.Base基础/3.Icon图标/操作/search备份
EN
文档
关于AntDB
部署与升级
快速入门
运维
调优
工具和插件
高级服务
数据安全
参考
  • 文档首页 /
  • 使用教程 /
  • SQL语言 /
  • 函数和操作符

函数和操作符

更新时间:2024-07-01 14:39:49

概论

AntDB 为内建的数据类型提供了大量的函数和操作符。 本章描述了其中的大部分内容,不过在手册的相关章节中还显示了更多的特殊用途函数。 用户也可以定义它们自己的函数和操作符。 adb 命令 \df\do 可以分别被用于显示所有可用的函数和操作符的列表。

本章中用于描述函数或操作符的参数和结果数据类型的符号如下所示:

repeat ( text, integer ) → text

函数 repeat 接受一个文本和一个整型参数,并返回文本类型的结果。右箭头也用于指示举例的结果,因此:

repeat('Pg', 4) → PgPgPgPg

逻辑操作符

常用的逻辑操作符有:

boolean AND boolean → boolean
boolean OR boolean → boolean
NOT boolean → boolean

SQL 使用三值的逻辑系统,包括真、假和 nullnull表示“未知”。观察下面的真值表:

aba AND ba OR b
TRUETRUETRUETRUE
TRUEFALSEFALSETRUE
TRUENULLNULLTRUE
FALSEFALSEFALSEFALSE
FALSENULLFALSENULL
NULLNULLNULLNULL
aNOT a
TRUEFALSE
FALSETRUE
NULLNULL

操作符 ANDOR 是可交换的,也就是说,可以交换左右操作数而不影响结果。 (但是,不能保证左操作数在右操作数之前计算。)

比较函数和操作符

常见的比较操作符都可用,如下表所示。

比较操作符

操作符描述
datatype < datatypeboolean小于
datatype > datatypeboolean大于
datatype <= datatypeboolean小于等于
datatype >= datatypeboolean大于等于
datatype = datatypeboolean等于
datatype <> datatypeboolean不等于
datatype != datatypeboolean不等于

注意

<> 表示 “not equal” 的标准的 SQL 符号。 != 是一个别名, 在解析的早期阶段被转换为 <> 。 因此, 它不可能实现 !=<> 操作符以做不同的事情。

这些比较操作符适用于所有具有自然排序的内置数据类型,包括数字、字符串、和日期/时间类型。 此外,如果它们的组件数据类型具有可比性,则可以比较阵列、复合类型和范围。

通常也可以比较相关数据类型的值;例如 integer > bigint 将起作用。 这种排序的某些情况直接由“cross-type” 比较操作符实现,但是,如果没有这种操作符,解析器将把不太通用的类型强制为更通用的类型,并应用后者的比较操作符。

如上所示,所有比较操作符都是二元操作符,返回 boolean 类型的值。 因此,类似 1 < 2 < 3 的表达式是无效的。因为没有<操作符与 3 进行 Boolean 值比较)。 使用下面显示的 BETWEEN 谓词执行范围测试。

如下表所示,也有一些比较谓词。它们的行为和操作符很像,但是具有 SQL 标准所要求的特殊语法。

比较谓词

谓词描述示例(s)
datatype BETWEEN datatype AND datatypeboolean之间(包括范围端点)。2 BETWEEN 1 AND 3t 2 BETWEEN 3 AND 1f
datatype NOT BETWEEN datatype AND datatypeboolean 不在之间 (BETWEEN 的否定)。2 NOT BETWEEN 1 AND 3f
datatype BETWEEN SYMMETRIC datatype AND datatypeboolean 之间, 在对两个端点值排序之后。2 BETWEEN SYMMETRIC 3 AND 1t
datatype NOT BETWEEN SYMMETRIC datatype AND datatypeboolean 不在之间,在对两个端点值排序之后。2 NOT BETWEEN SYMMETRIC 3 AND 1f
datatype IS DISTINCT FROM datatypeboolean 不相等, 将空(null)视为可比值。1 IS DISTINCT FROM NULLt (而不是 NULLNULL IS DISTINCT FROM NULLf (而不是 NULL
datatype IS NOT DISTINCT FROM datatypeboolean 相等,将空(null)视为可比值。1 IS NOT DISTINCT FROM NULLf (而不是 NULLNULL IS NOT DISTINCT FROM NULLt (而不是 NULL
datatype IS NULLboolean 测试值是否为空。1.5 IS NULLf
datatype IS NOT NULLboolean 测试值是否不为空。'null' IS NOT NULLt
datatype ISNULLboolean 测试值是否为空(非标准语法)。
datatype NOTNULLboolean 测试值是否不为空(非标准语法)。
boolean IS TRUEboolean 测试布尔表达式是否为真。true IS TRUEt NULL::boolean IS TRUEf (而不是 NULL)
boolean IS NOT TRUEboolean 测试布尔表达式是否为假或未知。true IS NOT TRUEf NULL::boolean IS NOT TRUEt (而不是 NULL
boolean IS FALSEboolean 测试布尔表达式是否为假。true IS FALSEf``NULL::boolean IS FALSEf(而不是 NULL
boolean IS NOT FALSEboolean 测试布尔表达式是否为真或未知。true IS NOT FALSEt NULL::boolean IS NOT FALSEt (而不是 NULL
boolean IS UNKNOWNboolean 测试布尔表达式是否为未知。true IS UNKNOWNf NULL::boolean IS UNKNOWNt(而不是 NULL
boolean IS NOT UNKNOWNboolean 测试布尔表达式是否为真或假。true IS NOT UNKNOWNt NULL::boolean IS NOT UNKNOWNf (而不是 NULL

BETWEEN 谓词可以简化范围测试:

a BETWEEN x AND y

等效于

a >= x AND a <= y

注意 BETWEEN 认为终点值是包含在范围内的。 BETWEEN SYMMETRIC 就像 BETWEEN,除了没有要求 AND 的左边的参数小于或等于右边的参数。 如果不是的话,这两个参数将自动交换,因此总是隐含一个非空范围。

BETWEEN 的各种变量都是以普通比较操作符的方式实现的,因此适用于任何可以比较的数据类型。

注意

BETWEEN 语法中使用 AND 会与使用 AND 作为逻辑操作符产生歧义。为了解决这个问题,只允许有限的一组表达类型作为 BETWEEN 子句的第二个参数。 如果需要在 BETWEEN 中写一个更复杂的子表达式,在子表达式两边写上圆括号。

当有一个输入为空时,普通的比较操作符会得到空(表示“未知”),而不是真或假。例如,7 = NULL 得到空,7 <> NULL 也一样。如果这种行为不合适,可以使用 IS [ NOT ] DISTINCT FROM 谓词:

a IS DISTINCT FROM b
a IS NOT DISTINCT FROM b

对于非空输入,IS DISTINCT FROM<> 操作符一样。不过,如果两个输入都为空,它会返回假。而如果只有一个输入为空,它会返回真。类似地,IS NOT DISTINCT FROM 对于非空输入的行为与 = 相同,但是当两个输入都为空时它返回真,并且当只有一个输入为空时返回假。因此,这些谓词实际上把空值当作一种普通数据值而不是“unknown”。

要检查一个值是否为空,使用下面的谓词:

expression IS NULL
expression IS NOT NULL

或者等效,但并不标准的谓词:

expression ISNULL
expression NOTNULL

不要*expression* = NULL,因为NULL是不“等于”NULL的(控制代表一个未知的值,因此无法知道两个未知的数值是否相等)。

提示

有些应用可能要求表达式*expression* = NULLexpression 得出空值时返回真。强烈建议这样的应用修改成遵循 SQL 标准。但是,如果这样修改不可能完成,那么可以使用配置变量 transform_null_equals。如果打开它,AntDB 将把 x = NULL 子句转换成 x IS NULL

如果 expression 是行值,那么当行表达式本身为非空值或者行的所有域为非空时 IS NULL 为真。由于这种行为,IS NULLIS NOT NULL 并不总是为行值表达式返回反转的结果,特别是,一个同时包含 NULL 和非空值的域将会对两种测试都返回假。在某些情况下,写成 row IS DISTINCT FROM NULL 或者 row IS NOT DISTINCT FROM NULL 会更好,它们只会检查整个行值是否为空而不需要在行的域上做额外的测试。

布尔值也可以使用下列谓词进行测试:

boolean_expression IS TRUE
boolean_expression IS NOT TRUE
boolean_expression IS FALSE
boolean_expression IS NOT FALSE
boolean_expression IS UNKNOWN
boolean_expression IS NOT UNKNOWN

这些谓词将总是返回真或假,从来不返回空值,即使操作数是空也如此。空值输入被当做逻辑值“未知”。 请注意实际上 IS UNKNOWNIS NOT UNKNOWN 分别与 IS NULLIS NOT NULL 相同, 只是输入表达式必须是布尔类型。

如下表所示,也有一些比较相关的函数可用。

比较函数

函数描述例子
num_nonnulls ( VARIADIC "any" ) → integer 返回非空参数的数量。num_nonnulls(1, NULL, 2)2
num_nulls ( VARIADIC "any" ) → integer 返回空参数的数量。num_nulls(1, NULL, 2)1

数学函数和操作符

AntDB 为很多类型提供了数学操作符。对于那些没有标准数学表达的类型(如日期/时间类型),将在后续小节中描述实际的行为。

下表显示了可用于标准数字类型的数学操作符。除非另有说明,显示为可接受 numeric_type 的操作符对所有的 smallintintegerbigintnumericrealdouble precision类型都可用。 显示为可接受 integral_type 的操作符对 smallintintegerbigint 类型是可用的。 除了特别说明之处,操作符的每种形式都返回与其参数相同的数据类型。 涉及多个参数数据类型的调用, 例如 integer + numeric,可通过使用这些列表中稍后出现的类型来解析。

数学操作符

操作符描述例子
numeric_type + numeric_type*numeric_type*2 + 35
+ numeric_type*numeric_type*一元加(无操作)+ 3.53.5
numeric_type - numeric_type*numeric_type*2 - 3-1
- numeric_type*numeric_type*否定- (-4)4
numeric_type * numeric_type*numeric_type*2 * 36
numeric_type / numeric_type*numeric_type*除(对于整型,除法将结果截断为零)5.0 / 22.5000000000000000``5 / 22``(-5) / 2-2
numeric_type % numeric_type*numeric_type*模(取余); 适用于 smallintintegerbigintnumeric 5 % 41
numeric ^ numericnumeric``double precision ^ double precisiondouble precision指数(不像典型的数学实践, 多次使用 ^ 将会从左到有关联)2 ^ 38``2 ^ 3 ^ 3512
|/ double precisiondouble precision 平方根 |/ 25.05
||/ double precisiondouble precision 立方根 ||/ 64.04
bigint !numeric阶乘(已弃用,使用 factorial() 代替)5 !120
!! bigintnumeric阶乘作为前缀操作符(已弃用,使用 factorial() 代替)!! 5120
@ numeric_type*numeric_type*绝对值@ -5.05
integral_type & integral_type*integral_type*按位与(AND)91 & 1511
integral_type | integral_type*integral_type*按位或(OR)32 | 335
integral_type # integral_type*integral_type*按位异或(exclusive OR)17 # 520
~ integral_type*integral_type*按位求反(NOT)~1-2
integral_type << integer*integral_type*按位左移 1 << 416
integral_type >> integer*integral_type*按位右移 8 >> 22

下表显示了可用的数学函数。 许多这样的函数以多种具有不同的参数类型的形式提供。 除非注明,任何给定形式的函数都返回与其参数相同的数据类型;跨类型情况的解决方法与上述对操作符的解释相同。 使用 double precision 数据的函数大多是在主机系统的C库上实现的;因此,边界情况下的准确性和行为会因主机系统的区别而不同。

数学函数

函数描述例子
abs ( numeric_type ) → *numeric_type* 绝对值 abs(-17.4)17.4
cbrt ( double precision ) → double precision 立方根 cbrt(64.0)4
ceil ( numeric ) → numeric ceil ( double precision ) → double precision 大于或等于参数的最接近的整数 ceil(42.2)43``ceil(-42.8)-42
ceiling ( numeric ) → numeric ceiling ( double precision ) → double precision 大于或等于参数的最接近的整数 (与 ceil 相同)ceiling(95.3)96
degrees ( double precision ) → double precision将弧度转换为角度degrees(0.5)28.64788975654116
div ( y numeric, x numeric ) → numericy/x 的整数商(截断为零位)div(9,4)2
exp ( numeric ) → numeric exp ( double precision ) → double precision指数(e 的给定次方)exp(1.0)2.7182818284590452
factorial ( bigint ) → numeric阶乘factorial(5)120
floor ( numeric ) → numeric floor ( double precision ) → double precision 小于或等于参数的最接近整数 floor(42.8)42 floor(-42.8)-43
gcd ( numeric_type, numeric_type ) → *numeric_type*最大公约数 (能将两个输入数整除而无余数的最大正数);如果两个输入为零则返回 0 ; 适用于 integer, bigint,和 numeric``gcd(1071, 462)21
lcm ( numeric_type, numeric_type ) → *numeric_type*最小公倍数(两个输入的整数倍的最小的严格正数);如果任意一个输入值为零则返回 0;适用于 integerbigintnumeric``lcm(1071, 462)23562
ln ( numeric ) → numeric``ln ( double precision ) → double precision 自然对数 ln(2.0)0.6931471805599453
log ( numeric ) → numeric``log ( double precision ) → double precision 以 10 为底的对数 log(100)2
log10 ( numeric ) → numeric``log10 ( double precision ) → double precision 以 10 为底的对数(与 log 相同)log10(1000)3
log ( b numeric, x numeric ) → numericb 为底的 x 的对数log(2.0, 64.0)6.0000000000
min_scale ( numeric ) → integer 精确表示所提供值所需的最小刻度(小数位数)min_scale(8.4100)2
mod ( y numeric_type, x numeric_type ) → *numeric_type*y/*x*的余数;适用于 smallintintegerbigintnumeric``mod(9,4)1
pi ( ) → double precision π 的近似值 pi()3.141592653589793
power ( a numeric, b numeric ) → numeric``power ( a double precision, b double precision ) → double precision ab 次幂 power(9, 3)729
radians ( double precision ) → double precision 将角度转换为弧度 radians(45.0)0.7853981633974483
round ( numeric ) → numeric round ( double precision ) → double precision 四舍五入到最近的整数 round(42.4)42
round ( v numeric, s integer ) → numericv 四舍五入到 s 位小数 round(42.4382, 2)42.44
scale ( numeric ) → integer 参数的刻度(小数点后的位数)scale(8.4100)4
sign ( numeric ) → numeric sign ( double precision ) → double precision 参数的符号(-1, 0或 +1)sign(-8.4)-1
sqrt ( numeric ) → numeric sqrt ( double precision ) → double precision 平方根 sqrt(2)1.4142135623730951
trim_scale ( numeric ) → numeric 通过删除尾数部分的零来降低值的刻度(小数位数) trim_scale(8.4100)8.41
trunc ( numeric ) → numeric trunc ( double precision ) → double precision 截断整数(向零靠近)trunc(42.8)42 trunc(-42.8)-42
trunc ( v numeric, s integer ) → numeric截断 vs 位小数位置的数字 trunc(42.4382, 2)42.43
width_bucket ( operand numeric, low numeric, high numeric, count integer ) → integer width_bucket ( operand double precision, low double precision, high double precision, count integer ) → integer 返回包含 count 等宽柱的柱状图中 operand 所在的柱的编号,范围从 lowhigh。 超出该范围的输入则返回 0* 计数 *+1width_bucket(5.35, 0.024, 10.06, 5)3
width_bucket ( operand anyelement, thresholds anyarray ) → integer 返回一个柱号,这个柱是在给定数组中 operand 将被分配的柱。对于一个低于第一个下界的输入返回 0operand 和数组元素可以是具有标准比较操作符的任何类型。 thresholds 数组必须被排好序,最小的排在最前面,否则将会得到意想不到的结果。width_bucket(now(), array['yesterday', 'today', 'tomorrow']::timestamptz[])2

下表展示了用于产生随机数的函数。

随机函数

函数描述例子
random ( ) → double precision 返回一个范围 0.0 <= x < 1.0 中的随机值 random()0.897124072839091
setseed ( double precision ) → void 为后续的 random() 调用设置种子;参数必须在 -1.0 和 1.0 之间,包括边界值 setseed(0.12345)

random() 函数使用了一个简单的线性共轭算法。 它的速度很快,但不适合于密码学应用。如果 setseed() 被调用,那么当前会话中的一系列后续 random() 调用的结果能够通过使用相同的参数重新发布 setseed() 来重复。

下表显示了可用的三角函数。 每一种这样的函数都有两个变体,一个以弧度度量角,另一个以角度度量角。

三角函数

函数描述例子
acos ( double precision ) → double precision 反余弦,结果为弧度 acos(1)0
acosd ( double precision ) → double precision 反余弦,结果为度数 acosd(0.5)60
asin ( double precision ) → double precision 反正弦,结果为弧度 asin(1)1.5707963267948966
asind ( double precision ) → double precision 反正弦,结果为度数 asind(0.5)30
atan ( double precision ) → double precision 反正切,结果为弧度 atan(1)0.7853981633974483
atand ( double precision ) → double precision 反正切,结果为度数 atand(1)45
atan2 ( y double precision, x double precision ) → double precisiony/x 的反正切,结果为弧度 atan2(1,0)1.5707963267948966
atan2d ( y double precision, x double precision ) → double precisiony/x 的反正切,结果为度数 atan2d(1,0)90
cos ( double precision ) → double precision 余弦,参数为弧度 cos(0)1
cosd ( double precision ) → double precision 余弦,参数为度数 cosd(60)0.5
cot ( double precision ) → double precision 余切,参数为弧度 cot(0.5)1.830487721712452
cotd ( double precision ) → double precision 余切,参数为度数 cotd(45)1
sin ( double precision ) → double precision 正弦,参数为弧度 sin(1)0.8414709848078965
sind ( double precision ) → double precision 正弦,参数为度数 sind(30)0.5
tan ( double precision ) → double precision 正切,参数为弧度 tan(1)1.5574077246549023
tand ( double precision ) → double precision 正切,参数为度数 tand(45)1

注意

另一种使用以角度度量的角的方法是使用早前展示的单位转换函数 radians()degrees()。不过,使用基于角度的三角函数更好,因为这类方法能避免 sind(30) 等特殊情况下的舍入偏差。

下表显示的是可用的双曲函数。

双曲函数

函数描述例子
sinh ( double precision ) → double precision 双曲正弦 sinh(1)1.1752011936438014
cosh ( double precision ) → double precision 双曲余弦 cosh(0)1
tanh ( double precision ) → double precision 双曲切线 tanh(1)0.7615941559557649
asinh ( double precision ) → double precision 反双曲正弦 asinh(1)0.881373587019543
acosh ( double precision ) → double precision 反双曲余弦 acosh(1)0
atanh ( double precision ) → double precision 反双曲切线 atanh(0.5)0.5493061443340548

字符串函数和操作符

本节描述了用于检查和操作字符串值的函数和操作符。 在这个环境中的串包括所有类型 charactercharacter varyingtext 的值。 除非特别说明,这些函数和操作符声明为接受并返回 text 类型。 他们将互换接受 character varying 参数。 在应用函数或操作符之前 character 类型的值将被转换为 text,结果删除 character 值中的任何末尾空格。

SQL 定义了一些字符串函数,它们使用关键字,而不是逗号来分隔参数。

注意

由于存在从那些数据类型到 text 的隐式强制措施,在 AntDB 8.3 之前,这些函数也可以接受多种非字符串数据类型。这些强制措施在目前的版本中已经被删除,因为它们常常导致令人惊讶的行为。不过,字符串串接操作符(||)仍然接受非字符串输入,只要至少一个输入是一种字符串类型,如下表所示。对于其他情况,如果需要复制之前的行为,可以为 text 插入一个显式强制措施。

SQL 字符串函数和操作符

函数/操作符描述例子
text || texttext 连接两个字符串。'Post' || 'greSQL'AntDB
text || anynonarraytext``anynonarray || texttext 将非字符串输入转换为文本,然后将两个字符串串联在一起。 (非字符串输入不能为数组类型,因为这将在||操作符的数组中造成歧义。如果想连接一个数组的文本相等的,请显式地将其转换为 text 。)'Value: ' || 42Value: 42
text IS [NOT] [form] NORMALIZEDboolean 检查字符串是否在指定的 Unicode 规范化表单中。 可选的 form 关键词指定表单:NFC (默认的)、NFDNFKCNFKD。 只有在服务器编码为 UTF8 时,才能使用此表达式。 请注意,使用这个表达式检查规范化通常比规范化可能已经规范化的字符串要快。U&'\0061\0308bc' IS NFD NORMALIZEDt
bit_length ( text ) → integer 返回字符串中的位数(8 倍于 octet_length)。bit_length('jose')32
char_length ( text ) → integer``character_length ( text ) → integer 返回字符串中的字符数。char_length('josé')4
lower ( text ) → text 根据数据库的语言环境规则,将字符串转换为全部小写。lower('TOM')tom
normalize ( text [, form ] ) → text 将字符串转换为指定的 Unicode 规范化形式。 可选的 form 关键字指定了如下形式:NFC (the default)、NFDNFKCNFKD。 该函数只能在服务器编码为 UTF8 时使用。normalize(U&'\0061\0308bc', NFC)U&'\00E4bc'
octet_length ( text ) → integer 返回字符串的字节数。octet_length('josé')5 (if server encoding is UTF8)
octet_length ( character ) → integer 返回字符串中的字节数。 由于此版本的函数直接接受 character 类型,它不会剥离尾随空格。octet_length('abc '::character(4))4
overlay ( string text PLACING newsubstring text FROM start integer [ FOR count integer ] ) → text 替换 *string*从 start 字符开始的子串,并用 newsubstring 扩展到 count 字符。 如果省略了 count,则默认为 newsubstring 的长度。overlay('Txxxxas' placing 'hom' from 2 for 4)Thomas
position ( substring text IN string text ) → integer 返回指定的 substringstring 起始索引,如果不存在则返回零。position('om' in 'Thomas')3
substring ( string text [ FROM start integer ] [ FOR count integer ] ) → text 如果已指定,提取 stringstart 字符开始的子串, 并且在 count 字符后停止。如果已指定的话。 提供至少一个 startcount 中的至少一个。substring('Thomas' from 2 for 3)hom substring('Thomas' from 3)omas substring('Thomas' for 2)Th
substring ( string text FROM pattern text ) → text 提取匹配 POSIX 正则表达式的子字符串。substring('Thomas' from '...$')→mas
substring ( string text FROM pattern text FOR escape text ) → text 提取匹配 SQL 正则表达式的字串。substring('Thomas' from '%#"o_a#"_' for '#')oma
trim ( [ LEADING
trim ( [ LEADING
upper ( text ) → text 根据数据库的定位规则,将字符串转换为所有大写。upper('tom')TOM

还有额外的串操作函数可以用,它们在下表中列出。

其他字符串函数

函数描述例子
ascii ( text ) → integer 返回参数的第一个字符的数字代码。在 UTF8 编码中,返回该字符的 Unicode 代码点。 在其他多字节编码中,该参数必须是一个 ASCII 字符。ascii('x')120
btrim ( string text [, characters text ] ) → textstring 的开头或结尾删除最长的只包含 characters(默认是一个空格)的字符串 btrim('xyxtrimyyx', 'xyz')trim
chr ( integer ) → text 返回给定代码的字符。在 UTF8 编码中该参数被视作一个 Unicode 代码点。 在其他多字节编码中该参数必须指定一个 ASCII 字符。 chr(0) 字符不被允许,因为文本数据类型不能存储这种字符。chr(65)A
concat ( val1 "any" [, val2 "any" [, ...] ] ) → text 连接所有参数的文本表示。空参数被忽略。concat('abcde', 2, NULL, 22)abcde222
concat_ws ( sep text, val1 "any" [, val2 "any" [, ...] ] ) → text 用分隔符连接除第一个参数外的所有参数。第一个参数用作分隔符字符串,不应为 NULL。其他 NULL 参数将被忽略。concat_ws(',', 'abcde', 2, NULL, 22)abcde,2,22
format ( formatstr text [, formatarg "any" [, ...] ] ) → text 根据格式字符串对参数进行格式化;functions-string.html#FUNCTIONS-STRING-FORMAT)。这个函数类似于 C 函数 sprintfformat('Hello %s, %1$s', 'World')Hello World, World
initcap ( text ) → text 将每个单词的第一个字母转换为大写,其余字母转换为小写。单词是由非字母数字字符分隔的字母数字字符序列。initcap('hi THOMAS')Hi Thomas
left ( string text, n integer ) → text 以字符串返回第一个 n 字符,或在 n 为负时, 返回最后
length ( text ) → integer 返回字符串中的字符数。length('jose')4
lpad ( string text, length integer [, fill text ] ) → textstring 扩展为长度 length,通过前置字符 fill(默认空格)。 如果 string 已经超过 length 那么它将被截断(在右侧)。lpad('hi', 5, 'xy')xyxhi
ltrim ( string text [, characters text ] ) → textstring 开始删除包含 characters(默认空格)中仅包含字符的最长字符串。ltrim('zzzytest', 'xyz')test
md5 ( text ) → text 计算参数的 MD5 hash ,结果以十六进制形式写入。md5('abc')900150983cd24fb0d6963f7d28e17f72
parse_ident ( qualified_identifier text [, strict_mode boolean DEFAULT true ] ) → text[] 将*qualified_identifier* 拆分为一个标识符数组,删除单个标识符的任何引用。 默认情况下,最后一个标识符之后的额外字符被视为错误;但是,如果第二个参数为 false,则忽略这些额外的字符。 (这种行为对于解析类似函数的对象的名称有作用) 请注意,此函数不会截断超长标识符。如果想截断,可以把结果给到 name[]parse_ident('"SomeSchema".someTable'){SomeSchema,sometable}
pg_client_encoding ( ) → name 返回当前客户端编码名称。pg_client_encoding()UTF8
quote_ident ( text ) → text 返回适合引用的给定字符串,作为 SQL 语句字符串中的标识符。 只有在必要的情况下才添加引号(例如,如果字符串包含非标识符字符或将被大小写折叠)。 嵌入的引号被适当地加双引号。quote_ident('Foo bar')"Foo bar"
quote_literal ( text ) → text 返回在 SQL 语句字符串中适当引用的给定字符串,用作字符串文字使用。 嵌入式单引号和反斜线适当的翻倍(转双引号或双斜线)。 请注意,quote_literal 返回无效输入;如果这个参数可能为空,quote_nullable 通常更合适。
quote_literal ( anyelement ) → text 将给定的值转换为文本,然后将其作为字面量引用。 内嵌的单引号和反斜杠被适当地翻倍。quote_literal(42.5)'42.5'
quote_nullable ( text ) → text 返回在 SQL 语句字符串中适当引用的给定字符串文字;或者,如果参数为 null,则返回 NULL。 内嵌的单引号和反斜杠被适当地翻倍。plpgsql-statements.html#PLPGSQL-QUOTE-LITERAL-EXAMPLE)。quote_nullable(NULL)NULL
quote_nullable ( anyelement ) → text 将给定值转换为文本,然后将其作为字面量引用;或者,如果参数为 null,则返回 NULL。 内嵌的单引号和反斜杠被适当地翻倍。quote_nullable(42.5)'42.5'
regexp_match ( string text, pattern text [, flags text ] ) → text[] 返回从 POSIX 正则表达式到 string 的第一个匹配中捕获的子字符串。regexp_match('foobarbequebaz', '(bar)(beque)'){bar,beque}
regexp_matches ( string text, pattern text [, flags text ] ) → setof text[] 返回通过将 POSIX 正则表达式与 string 匹配而捕获的子字符串;regexp_matches('foobarbequebaz', 'ba.', 'g') →``` {bar} {baz} `
regexp_replace ( string text, pattern text, replacement text [, flags text ] ) → text 替换匹配 POSIX 正则表达式的子字符串;节](functions-matching.html#FUNCTIONS-POSIX-REGEXP)。regexp_replace('Thomas', '.[mN]a.', 'M')ThM
regexp_split_to_array ( string text, pattern text [, flags text ] ) → text[] 使用 POSIX 正则表达式作为分隔符拆分*string*; regexp_split_to_array('hello world', '\s+'){hello,world}
regexp_split_to_table ( string text, pattern text [, flags text ] ) → setof text 使用 POSIX 正则表达式作为分隔符拆分*string*;regexp_split_to_table('hello world', '\s+') →``` hello world `
repeat ( string text, number integer ) → text 重复 string 指定 number 的次数。repeat('Pg', 4)PgPgPgPg
replace ( string text, from text, to text ) → textstring 中当前的子串 from 替换为子串 toreplace('abcdefabcdef', 'cd', 'XX')abXXefabXXef
reverse ( text ) → text 颠倒字符串中字符的顺序。reverse('abcde')edcba
right ( string text, n integer ) → text 返回字符串中的最后 n 个字符,或者在 n>为负时,返回除了前面的
rpad ( string text, length integer [, fill text ] ) → text 扩展 string 到长度 length,通过追加 fill 字符(默认为空格)。如果 string 已经比 length 长,则截断它。rpad('hi', 5, 'xy')hixyx
rtrim ( string text [, characters text ] ) → textstring 末尾删除包含 characters(默认为空格)中仅包含字符的最长字符串。rtrim('testxxzx', 'xyz')test
split_part ( string text, delimiter text, n integer ) → textdelimiter 出现时拆分 string,并且返回第 n 个字段(从一计数)。split_part('abc~@~def~@~ghi', '~@~', 2)def
strpos ( string text, substring text ) → integer 返回在 string 中指定的 substring 的起始索引,如果不存在则为零。 (与(*substring* 在 *string*中的)位置相同,但是请注意反转的参数顺序)strpos('high', 'ig')2
substr ( string text, start integer [, count integer ] ) → text 提取 stringstart 字符开始的子字符串,并扩展 count 字符,如果指定了的话。 (与 子字符串(*string* 从 *start* 开始计数 *count*)相同。)substr('alphabet', 3)phabet``substr('alphabet', 3, 2)ph
starts_with ( string text, prefix text ) → boolean 如果 stringprefix 开始就返回真。starts_with('alphabet', 'alph')t
to_ascii ( string text ) → text``to_ascii ( string text, encoding name ) → text``to_ascii ( string text, encoding integer ) → textstring 从另一个编码中转换为 ASCII,该编码可按名称或编号标识。 如果 encoding 被省略,则假定数据库编码(这在实践中是唯一有用的案例)。转换主要包括降音。 转换仅支持来自 LATIN1LATIN2LATIN9WIN1250 的编码。 (其他请参见 unaccent 模块,更灵活的解决方案。)to_ascii('Karél')Karel
to_hex ( integer ) → text``to_hex ( bigint ) → text 将数字转换为其相应的十六进制表示形式。to_hex(2147483647)7fffffff
translate ( string text, from text, to text ) → textstring 中与 from 集合中匹配的每个字符替换为 to 集合中相应的字符。 如果 from 长于 tofrom 中出现的额外字符被删除。translate('12345', '143', 'ax')a2x5

concatconcat_wsformat 函数是可变的,因此可以把要串接或格式化的值作为一个标记了 VARIADIC 关键字的数组进行传递。 数组的元素被当作函数的独立普通参数一样处理。如果可变数组参数为 NULL,concatconcat_ws 返回 NULL,但 format 把 NULL 当作一个零元素数组。

format

函数 format 根据一个格式字符串产生格式化的输出,其形式类似于 C 函数 sprintf

format(formatstr text [, formatarg "any" [, ...] ])

formatstr 是一个格式字符串,它指定了结果应该如何被格式化。格式字符串中的文本被直接复制到结果中,除了使用格式说明符的地方。格式说明符在字符串中扮演着占位符的角色,它定义后续的函数参数如何被格式化及插入到结果中。每一个 formatarg 参数会被根据其数据类型的常规输出规则转换为文本,并接着根据格式说明符被格式化和插入到结果字符串中。

格式说明符由一个%字符开始并且有这样的形式

%[position][flags][width]type

其中的各组件域是:

  • position(可选)

    一个形式为*n*$的字符串,其中 n 是要打印的参数的索引。索引 1 表示 formatstr 之后的第一个参数。如果 position 被忽略,默认会使用序列中的下一个参数。

  • flags(可选)

    控制格式说明符的输出如何被格式化的附加选项。当前唯一支持的标志是一个负号(-),它将导致格式说明符的输出会被左对齐(left-justified)。除非 width 域也被指定,否者这个域不会产生任何效果。

  • width(可选)

    指定用于显示格式说明符输出的最小字符数。输出将被在左部或右部(取决于-标志)用空格填充以保证充满该宽度。太小的宽度设置不会导致输出被截断,但是会被简单地忽略。宽度可以使用下列形式之一指定:一个正整数;一个星号(*)表示使用下一个函数参数作为宽度;或者一个形式为 **n*$的字符串表示使用第 n 个函数参数作为宽度。如果宽度来自于一个函数参数,则参数在被格式说明符的值使用之前就被消耗掉了。如果宽度参数是负值,结果会在长度为 abs(width) 的域中被左对齐(如果-标志被指定)。

  • type(必需)

    格式转换的类型,用于产生格式说明符的输出。支持下面的类型:s 将参数值格式化为一个简单字符串。一个控制被视为一个空字符串。I 将参数值视作 SQL 标识符,并在必要时用双写引号包围它。如果参数为空,将会是一个错误(等效于quote_ident)。L 将参数值引用为 SQL 文字。一个空值将被显示为不带引号的字符串 NULL(等效于 quote_nullable)。

除了以上所述的格式说明符之外,要输出一个文字形式的%字符,可以使用特殊序列%%

下面有一些基本的格式转换的例子:

SELECT format('Hello %s', 'World');
结果:Hello World

SELECT format('Testing %s, %s, %s, %%', 'one', 'two', 'three');
结果:Testing one, two, three, %

SELECT format('INSERT INTO %I VALUES(%L)', 'Foo bar', E'O\'Reilly');
结果:INSERT INTO "Foo bar" VALUES('O''Reilly')

SELECT format('INSERT INTO %I VALUES(%L)', 'locations', 'C:\Program Files');
结果:INSERT INTO locations VALUES(E'C:\\Program Files')

下面是使用 width 域和-标志的例子:

SELECT format('|%10s|', 'foo');
结果:|       foo|

SELECT format('|%-10s|', 'foo');
结果:|foo       |

SELECT format('|%*s|', 10, 'foo');
结果:|       foo|

SELECT format('|%*s|', -10, 'foo');
结果:|foo       |

SELECT format('|%-*s|', 10, 'foo');
结果:|foo       |

SELECT format('|%-*s|', -10, 'foo');
结果:|foo       |

这些例子展示了 position 域的例子:

SELECT format('Testing %3$s, %2$s, %1$s', 'one', 'two', 'three');
结果:Testing three, two, one

SELECT format('|%*2$s|', 'foo', 10, 'bar');
结果:|       bar|

SELECT format('|%1$*2$s|', 'foo', 10, 'bar');
结果:|       foo|

不同于标准的 C 函数 sprintf,AntDB 的 format 函数允许将带有或者不带有 position 域的格式说明符被混在同一个格式字符串中。一个不带有 position 域的格式说明符总是使用最后一个被消耗的参数的下一个参数。另外,format 函数不要求所有函数参数都被用在格式字符串中。例如:

SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
结果:Testing three, two, three

对于安全地构造动态 SQL 语句,%I%L 格式说明符特别有用。

二进制串函数和操作符

本节描述那些检查和操作二进制字符串的函数和操作符,这是类型 bytea 的值。 其中许多函数在用途和语法上都与上一节中描述的文本字符串函数等效。

SQL 定义了一些使用关键字而不是逗号来分割参数的串函数。AntDB 也提供了这些函数使用常规函数调用语法的版本。

SQL 二进制串函数和操作符

函数/操作符描述例子
bytea || byteabytea 连接两个二进制字符串。'\x123456'::bytea || '\x789a00bcde'::bytea\x123456789a00bcde
bit_length ( bytea ) → integer 返回二进制字符串中的位数 (8 倍于 octet_length)。bit_length('\x123456'::bytea)24
octet_length ( bytea ) → integer 返回二进制字符串中的字节数。octet_length('\x123456'::bytea)3
overlay ( bytes bytea PLACING newsubstring bytea FROM start integer [ FOR count integer ] ) → byteabytes 的子字符串替换为 newsubstring,该子字符串从 start 字节开始,并以 count 字节扩展。 如果忽略了 count,则默认为 newsubstring 的长度。overlay('\x1234567890'::bytea placing '\002\003'::bytea from 2 for 3)\x12020390
position ( substring bytea IN bytes bytea ) → integer 返回指定的 substringbytes 内的起始索引,如果不存在,则为零。position('\x5678'::bytea in '\x1234567890'::bytea)3
substring ( bytes bytea [ FROM start integer ] [ FOR count integer ] ) → bytea 提取 bytesstart 字节开始的子字符串,如果指定了,并且在 count 字节之后停止,如果指定了的话。 至少提供 startcount 中的一个。substring('\x1234567890'::bytea from 3 for 2)\x5678
trim ( [ BOTH ] bytesremoved bytea FROM bytes bytea ) → byteabytes 的开始和结束处删除 bytesremoved 中只包含字节的最长字符串。trim('\x9012'::bytea from '\x1234567890'::bytea)\x345678
trim ( [ BOTH ] [ FROM ] bytes bytea, bytesremoved bytea ) → bytea 这是 trim() 的非标准语法。trim(both from '\x1234567890'::bytea, '\x9012'::bytea)\x345678

其他二进制串函数

函数描述例子
btrim ( bytes bytea, bytesremoved bytea ) → byteabytes 的开始和结束处删除只包含 bytesremoved 中出现的字节的最长字符串btrim('\x1234567890'::bytea, '\x9012'::bytea)\x345678
get_bit ( bytes bytea, n bigint ) → integer 从二进制字符串中提取 n'th 位。get_bit('\x1234567890'::bytea, 30)1
get_byte ( bytes bytea, n integer ) → integer 从二进制字符串中提取 n'th 字节。get_byte('\x1234567890'::bytea, 4)144
length ( bytea ) → integer 返回二进制字符串中的字节数。length('\x1234567890'::bytea)5
length ( bytes bytea, encoding name ) → integer 返回二进制字符串中的字符数,假设它是给定 encoding 中的文本。length('jose'::bytea, 'UTF8')4
md5 ( bytea ) → text 计算二进制字符串的 MD5 hash,结果以十六进制形式写入。md5('Th\000omas'::bytea)8ab2d3c9689aaf18b4958c334c82d8b1
set_bit ( bytes bytea, n bigint, newvalue integer ) → bytea 设置二进制字符串中的 n'th 位为 newvalueset_bit('\x1234567890'::bytea, 30, 0)\x1234563890
set_byte ( bytes bytea, n integer, newvalue integer ) → bytea 设置二进制字符串中的 n'th 字节到 newvalueset_byte('\x1234567890'::bytea, 4, 64)\x1234567840
sha224 ( bytea ) → bytea 计算二进制字符串的 SHA-224 hashsha224('abc'::bytea)\x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7
sha256 ( bytea ) → bytea 计算二进制字符串的 SHA-256 hashsha256('abc'::bytea)\xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
sha384 ( bytea ) → bytea 计算二进制字符串的 SHA-384 hashsha384('abc'::bytea)\xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7
sha512 ( bytea ) → bytea 计算二进制字符串的 SHA-512 hashsha512('abc'::bytea)\xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
substr ( bytes bytea, start integer [, count integer ] ) → byteastart 字节开始提取 bytes 的子字符串,并扩展为 count 字节,如果这是指定的。(与 substring(*bytes* 从 *start* 到 *count*) 相同。)substr('\x1234567890'::bytea, 3, 2)\x5678

函数 get_byteset_byte 把一个二进制串中的一个字节计数为字节 0。 函数 get_bitset_bit 在每一个字节中从右边起计数位; 例如位 0 是第一个字节的最低有效位,而位 15 是第二个字节的最高有效位。

由于历史原因,函数 md5 返回的是一个十六进制编码的 text 值,而 SHA-2 函数返回类型 bytea。 可以使用函数encodedecode在两者之间转换。 例如encode(sha256('abc'),'hex')可以得到一个十六进制编码的文本表示,或者 decode(md5('abc'), 'hex')得到一个 bytea 值。

用于在不同字符集(编码)之间转换字符串的函数,以及用于以文本形式表示任意二进制数据的函数,在下表中显示。 对于这些函数,类型为 text 的参数或结果表示为数据库的默认编码,而类型为 bytea 的参数或结果表示为由另一个参数命名的编码。

Text/Binary String Conversion Functions

函数描述例子
convert ( bytes bytea, src_encoding name, dest_encoding name ) → bytea 将表示编码 src_encoding 的文本的二进制字符串转换为编码 dest_encoding 的二进制字符串。convert('text_in_utf8', 'UTF8', 'LATIN1')\x746578745f696e5f75746638
convert_from ( bytes bytea, src_encoding name ) → text 将表示编码 src_encoding 的文本的二进制字符串转换为数据库编码中的 textconvert_from('text_in_utf8', 'UTF8')text_in_utf8
convert_to ( string text, dest_encoding name ) → byteatext 字符串(数据库编码)转换为编码 dest_encoding 中编码的二进制字符串。convert_to('some_text', 'UTF8')\x736f6d655f74657874
encode ( bytes bytea, format text ) → text 将二进制数据编码成文本表示;支持的 format 值为: base64, escape, hex.encode('123\000\001', 'base64')MTIzAAE=
decode ( string text, format text ) → bytea 从文本表示中解码二进制数据;支持的 format 值与 encode 相同。decode('MTIzAAE=', 'base64')\x3132330001

encodedecode 函数支持以下文本格式:

  • base64

    base64 格式是 RFC 2045 Section 6.8。 根据 RFC,编码的行被分割为 76 个字符。但是,作为 MIME CRLF 行结束标记的替代,只有换行符用于行结束。 decode 函数忽略回车、换行、空格和制表符。 否则,当 decode 被提供了无效的 base64 数据—包括结尾填充不正确时。

  • escape

    escape 格式将零字节和设置了高位的字节转换为八进制转义序列(\nnn),并将反斜杠加倍。 其他字节值按字面意思表示。 decode 函数如果反斜杠后面没有第二个反斜杠或三个八进制数字将引发错误;它接受其他未变化的字节值。

  • hex

    hex 格式将每 4 位数据表示为一个十六进制数字,从 0f,首先写入每个字节的高阶数字。 encode 函数输出 a-f 的十六进制小写数字。 因为数据的最小单位是 8 位,所以 encode 总是返回偶数个字符。 decode 函数接受大写或小写的 a-f 字符。 当 decode 给出无效的十六进制数据—时将引发一个错误,包括给定奇数个字符时。

位串函数和操作符

本节描述用于检查和操作位串的函数和操作符,也就是操作类型为 bitbit varying 的值的函数和操作符。(虽然这些表中只提到了 bit 类型,但 bit varying 类型的值可以互换使用。)

位串操作符

操作符描述例子
bit || bitbit 连接 B'10001' || B'011'10001011
bit & bitbit 按位与(输入的长度必须相等)B'10001' & B'01101'00001
bit | bitbit 按位或 (输入的长度必须相等)B'10001' | B'01101'11101
bit # bitbit 按位异或 (输入的长度必须相等)B'10001' # B'01101'11100
~ bitbit 按位求反 ~ B'10001'01110
bit << integerbit 按位左移(字符串长度被保留)B'10001' << 301000
bit >> integerbit 按位右移(字符串长度被保留)B'10001' >> 200100

位字符串函数

函数描述例子
bit_length ( bit ) → integer 返回位字符串中的位数。bit_length(B'10111')5
length ( bit ) → integer 返回位字符串中的位数。length(B'10111')5
octet_length ( bit ) → integer 返回位字符串中的字节数。octet_length(B'1011111011')2
overlay ( bits bit PLACING newsubstring bit FROM start integer [ FOR count integer ] ) → bit 替换从 start 位开始的 bits 的子字符串,并将 newsubstring 扩展 count 位。 如果 count 被省略,默认为 newsubstring 的长度。overlay(B'01010101010101010' placing B'11111' from 2 for 3)0111110101010101010
position ( substring bit IN bits bit ) → integer 按返回指定 substring 的起始索引,以 bits 为单位,如果不存在则返回 0。position(B'010' in B'000001101011')8
substring ( bits bit [ FROM start integer ] [ FOR count integer ] ) → bit 如果指定了起始位,则提取从 start 位开始的 bits 的子字符串,如果指定了计数位,则在 count 位之后停止。 startcount 至少提供一个。substring(B'110010111111' from 3 for 2)00
get_bit ( bits bit, n integer ) → integer 从位字符串中提取第 n 位;第一个(最左)位为第 0 位。get_bit(B'101010101010101010', 6)1
set_bit ( bits bit, n integer, newvalue integer ) → bit 将位字符串中的第 n 位设置为 newvalue;第一个(最左)位是第 0 位。set_bit(B'101010101010101010', 6, 0)101010001010101010

另外,可以在整数和 bit 之间来回转换。 将一个整数转换为 bit(n) 会复制最右边的 n 位。 将一个整数转换为比整数本身更宽的位字符串宽度将在左边进行符号扩展。一些例子:

44::bit(10)                    0000101100
44::bit(3)                     100
cast(-44 as bit(12))           111111010100
'1110'::bit(4)::integer        14

请注意,如果只是转换为“bit”,意思是转换成 bit(1),因此只会转换整数的最低有效位。

模式匹配

AntDB 提供了三种独立的实现模式匹配的方法:SQL LIKE 操作符、更近一些的 SIMILAR TO 操作符(SQL:1999 里添加进来的)和 POSIX- 风格的正则表达式。除了这些基本的“这个串匹配这个模式吗?”操作符外,还有一些函数可用于提取或替换匹配子串并在匹配位置分离一个串。

提示

如果模式匹配的要求超出了这些,请考虑用 Perl 或 Tcl 写一个用户定义的函数。

小心

虽然大部分的正则表达式搜索都能被很快地执行,但是正则表达式仍可能被 人为地弄成需要任意长的时间和任意量的内存进行处理。要当心从不怀好意 的来源接受正则表达式搜索模式。如果必须这样做,建议加上语句超时限制。

使用 SIMILAR TO 模式的搜索具有同样的安全性危险, 因为 SIMILAR TO 提供了很多和 POSIX- 风格正则表达式相同的能力。

LIKE 搜索比其他两种选项简单得多,因此在使用不怀好意的模式来源时要更安全些。

这三种类型的模式匹配算子都不支持非确定性拼贴。 如果需要的话,可以在表达式中应用不同的拼贴来绕过这个限制。

LIKE

string LIKE pattern [ESCAPE escape-character]
string NOT LIKE pattern [ESCAPE escape-character]

如果该 string 匹配了提供的 pattern,那么 LIKE 表达式返回真(和预期的一样,如果 LIKE 返回真,那么 NOT LIKE 表达式返回假, 反之亦然。一个等效的表达式是 NOT (*string* LIKE *pattern*))。

如果 pattern 不包含百分号或者下划线,那么该模式只代表它本身的串;这时候 LIKE 的行为就象等号操作符。在 pattern 里的下划线 (_)代表(匹配)任何单个字符; 而一个百分号(%)匹配任何零或更多个字符的序列。

一些例子:

'abc' LIKE 'abc'    true
'abc' LIKE 'a%'     true
'abc' LIKE '_b_'    true
'abc' LIKE 'c'      false

LIKE 模式匹配总是覆盖整个串。因此,要匹配在串内任何位置的序列,该模式必须以百分号开头和结尾。

要匹配文本的下划线或者百分号,而不是匹配其它字符, 在 pattern 里相应的字符必须 前导逃逸字符。缺省的逃逸字符是反斜线,但是可以用 ESCAPE 子句指定一个不同的逃逸字符。 要匹配逃逸字符本身,写两个逃逸字符。

注意

如果关掉了 standard_conforming_strings,在文串常量中写的任何反斜线都需要被双写。

请注意反斜线在串文本里已经有特殊含义了,所以如果写一个 包含反斜线的模式常量,那就要在 SQL 语句里写两个反斜线。 因此,写一个匹配单个反斜线的模式实际上要在语句里写四个反斜线。 可以通过用 ESCAPE 选择一个不同的逃逸字符 来避免这样;这样反斜线就不再是 LIKE 的特殊字符了。 但仍然是字符文本分析器的特殊字符,所以还是需要两个反斜线。 也可以通过写 ESCAPE '' 的方式不选择逃逸字符,这样可以有效地禁用逃逸机制,但是没有办法关闭下划线和百分号在模式中的特殊含义。

根据 SQL 标准,省略 ESCAPE 意味着没有转义字符(而不是默认为反斜杠),并且不允许使用零长度的 ESCAPE 值。 因此,AntDB 在这方面的行为有点不标准。

关键字 ILIKE 可以用于替换 LIKE, 它令该匹配根据活动区域成为大小写无关。这个不属于 SQL 标准而是一个 AntDB 扩展。

操作符~~等效于 LIKE, 而~~*对应 ILIKE。 还有 !~~!~~*操作符分别代表 NOT LIKENOT ILIKE。 所有这些操作符都是 AntDB 特有的。 可能会在 EXPLAIN 输出和类似的地方看到这些操作符名称,因为解析器实际上将 LIKE 等翻译成这些运算符。

短语LIKEILIKENOT LIKENOT ILIKE 在 AntDB 语法中通常被视为操作符; 例如,它们可以用于 expression operator 的任何(subquery)构造,尽管这里不能包含 ESCAPE 子句。 在某些晦涩难懂的情况下,可能需要用底层操作符名称替代。

还可参见前缀操作符^@和相应的 starts_with 函数,在需要简单匹配字符串开头的情况下比较有用。

SIMILAR TO 正则表达式

string SIMILAR TO pattern [ESCAPE escape-character]
string NOT SIMILAR TO pattern [ESCAPE escape-character]

SIMILAR TO 操作符根据自己的模式是否匹配给定串而返回真或者假。 它和 LIKE 非常类似,只不过它使用 SQL 标准定义的正则表达式理解模式。 SQL 正则表达式是在 LIKE 标记和普通的(POSIX)正则表达式标记的奇怪的杂交。

类似 LIKESIMILAR TO 操作符只有在它的模式匹配整个串的时候才能成功;这一点和普通的 正则表达式的行为不同,在普通的正则表达式里,模式匹配串的任意部分。 和 LIKE 类似的地方还有,SIMILAR TO 使用_%作为分别代表任意单个字符和任意串的通配符(这些可以比得上 POSIX 正则表达式里的..*)。

除了这些从 LIKE 借用的功能之外,SIMILAR TO 支持下面这些从 POSIX 正则表达式借用的模式匹配元字符:

  • |表示选择(两个候选之一)。
  • *表示重复前面的项零次或更多次。
  • +表示重复前面的项一次或更多次。
  • ?表示重复前面的项零次或一次。
  • {m}表示重复前面的项刚好*m*次。
  • {m,}表示重复前面的项*m*次或更多次。
  • {m,n}表示重复前面的项至少 m 次并且不超过 n 次。
  • 可以使用圆括号()把多个项组合成一个逻辑项。
  • 一个方括号表达式[...]声明一个字符类,就像 POSIX 正则表达式一样。

注意点号(.)不是 SIMILAR TO 的一个元字符。

LIKE 一样,反斜杠将禁用这些元字符的特殊含义。 可以用 ESCAPE 来指定不同的转义字符,或者可以通过写 ESCAPE '' 来禁用转义功能。

根据 SQL 标准,省略 ESCAPE 意味着没有转义字符(而不是默认为反斜杠),并且不允许使用零长度的 ESCAPE 值。 AntDB 在这方面的行为有点不标准。

另一个非标准扩展是,在转义字符后面跟着一个字母或数字提供了对为 POSIX 正则表达式定义的转义序列的访问。

一些例子:

'abc' SIMILAR TO 'abc'          true
'abc' SIMILAR TO 'a'            false
'abc' SIMILAR TO '%(b|d)%'      true
'abc' SIMILAR TO '(b|c)%'       false
'-abc-' SIMILAR TO '%\mabc\M%'  true
'xabcy' SIMILAR TO '%\mabc\M%'  false

带有三个参数的 substring 函数可以提取匹配 SQL 正则表达式模式的子字符串。 该函数可以按照 SQL99 语法编写。

substring(string from pattern for escape-character)

或作为一个普通的三参数函数:

substring(string, pattern, escape-character)

SIMILAR TO 一样,指定的模式必须与整个数据字符串匹配,否则函数失败并返回空值。 为了表示匹配的数据子字符串的模式中,模式中应该包含两个转义字符的出现,并在后面加上一个双引号(")。 匹配成功后,将返回与这些分隔符之间的模式部分匹配的文本。

转义-双引号分隔符实际上是 将子字符串的模式分成三个独立的 正则表达式;例如,竖条(|) 三节中的任何一节只影响到该节。 此外,第一节和第三种正则表达式的定义是为了匹配最小的 尽可能多的文字,而不是最大的文字,当有歧义的时候,就不应该是最大的文字。关于有多少数据字符串符合哪种模式。(在 POSIX 术语中,第一和第三种正则表达式被强行规定为非贪婪)。

作为对 SQL 标准的扩展,AntDB 只允许有一个转义双引号分隔符,在这种情况下,第三个正则表达式被视为空;或者没有分隔符,在这种情况下,第一个和第三个正则表达式被视为空。

一些例子,使用#"定界返回串:

substring('foobar' from '%#"o_b#"%' for '#')   oob
substring('foobar' from '#"o_b#"%' for '#')    NULL

POSIX 正则表达式

下表列出了所有可用于 POSIX 正则表达式模式匹配的操作符。

正则表达式匹配操作符

操作符描述例子
text ~ textboolean 字符串匹配正则表达式,大小写敏感'thomas' ~ '.*thom.*'t
text ~* textboolean 字符串匹配正则表达式,大小写不敏感'thomas' ~* '.*Thom.*'t
text !~ textboolean 字符串不匹配正则表达式,大小写敏感'thomas' !~ '.*thomas.*'f
text !~* textboolean字符串不匹配正则表达式,大小写不敏感'thomas' !~* '.*vadim.*'t

POSIX 正则表达式提供了比 LIKESIMILAR TO 操作符更强大的含义。许多 Unix 工具,例如 egrepsedawk 使用一种与这里描述的类似的模式匹配语言。

正则表达式是一个字符序列,它是定义一个串集合 (一个正则集)的缩写。 如果一个串是正则表达式描述的正则集中的一员时, 就说这个串匹配该正则表达式。 和 LIKE 一样,模式字符准确地匹配串字符, 除非在正则表达式语言里有特殊字符 — 不过正则表达式用的 特殊字符和 LIKE 用的不同。 和 LIKE 模式不一样的是,正则表达式允许匹配串里的任何位置,除非该正则表达式显式地挂接在串的开头或者结尾。

一些例子:

'abc' ~ 'abc'    true
'abc' ~ '^a'     true
'abc' ~ '(b|d)'  true
'abc' ~ '^(b|c)' false

POSIX 模式语言的详细描述见下文。

带两个参数的 substring 函数,即 substring(*string* from *pattern*),提供了抽取一个匹配 POSIX 正则表达式模式的子串的方法。如果没有匹配它返回空值,否则就是文本中匹配模式的那部分。 但是如果该模式包含任何圆括号,那么将返回匹配第一对子表达式(对应第一个左圆括号的) 的文本。如果想在表达式里使用圆括号而又不想导致这个例外,那么可以在整个表达式外边放上一对圆括号。 如果需要在想抽取的子表达式前有圆括号,参阅后文描述的非捕获性圆括号。

一些例子:

substring('foobar' from 'o.b')     oob
substring('foobar' from 'o(.)b')   o

regexp_replace 函数提供了将匹配 POSIX 正则表达式模式的子串替换为新文本的功能。 它的语法是 regexp_replace(source, pattern, replacement [, flags ])。 如果没有匹配 pattern,那么返回不加修改的 source 串。 如果有匹配,则返回的 source 串里面的匹配子串将被 replacement 串替换掉。replacement 串可以包含\n, 其中\n是 1 到 9, 表明源串里匹配模式里第 n 个圆括号子表达式的子串应该被插入,并且它可以包含\&表示应该插入匹配整个模式的子串。如果需要放一个文字形式的反斜线在替换文本里,那么写\\flags 参数是一个可选的文本串,它包含另个或更多单字母标志,这些标志可以改变函数的行为。标志 i 指定大小写无关的匹配,而标志 g 指定替换每一个匹配的子串而不仅仅是第一个。

一些例子:

regexp_replace('foobarbaz', 'b..', 'X')
                                   fooXbaz
regexp_replace('foobarbaz', 'b..', 'X', 'g')
                                   fooXX
regexp_replace('foobarbaz', 'b(..)', 'X\1Y', 'g')
                                   fooXarYXazY

regexp_match 返回一个文本数组,它包含一个 POSIX 正则表达式模式与一个字符串第一个匹配所得到的子串。其语法是 regexp_match(string, pattern [, flags ])。如果没有匹配,则结果为 NULL。如果找到一个匹配并且 pattern 不包含带括号的子表达式,那么结果是一个单一元素的文本数组,其中包含匹配整个模式的子串。如果找到一个匹配并且 pattern 含有带括号的子表达式,那么结果是一个文本数组,其中第 n 个元素是与 pattern 的第 n 个圆括号子表达式匹配的子串(“非捕获”圆括号不计入在内,详见下文)。flags 参数是一个可选的文本字符串,它包含零个或者更多个可以改变该函数行为的单字母标志。

一些例子:

SELECT regexp_match('foobarbequebaz', 'bar.*que');
 regexp_match
--------------
 {barbeque}
(1 row)

SELECT regexp_match('foobarbequebaz', '(bar)(beque)');
 regexp_match
--------------
 {bar,beque}
(1 row)

在通常情况下,人们只是想要的大整个匹配的子串或者 NULL(没有匹配),可以写成这样

SELECT (regexp_match('foobarbequebaz', 'bar.*que'))[1];
 regexp_match
--------------
 barbeque
(1 row)

regexp_matches 函数返回一个文本数组的集合,其中包含着一个 POSIX 正则表达式模式与一个字符串匹配得到的子串。它和regexp_match 具有相同的语法。如果没有匹配,这个函数不会返回行。如果有一个匹配并且给定了 g 标志,则返回一行。如果有 N 个匹配并且给定了 g 标志,则返回 N 行。每一个返回的行都是一个文本数组,其中含有整个匹配的子串或者匹配 pattern 的圆括号子表达式的子串,这和上面对 regexp_match 的介绍一样。

一些例子:

SELECT regexp_matches('foo', 'not there');
 regexp_matches
----------------
(0 rows)

SELECT regexp_matches('foobarbequebazilbarfbonk', '(b[^b]+)(b[^b]+)', 'g');
 regexp_matches
----------------
 {bar,beque}
 {bazil,barf}
(2 rows)

提示

在大部分情况下,regexp_matches() 应该与 g 标志一起使用,因为如果只是想要第一个匹配,使用 regexp_match() 会更加简单高效。不过,regexp_match() 仅存在于 AntDB 版本 10 以及更高的版本中。当在较老的版本中使用时,一种常用的技巧是把regexp_matches() 调用放在子选择中,例如:

SELECT col1, (SELECT regexp_matches(col2, '(bar)(beque)')) FROM tab;

如果有一个匹配,则这个语句会产生一个文本数组,否则返回 NULL,这和 regexp_match() 的做法一样。如果没有子选择,这个查询对于没有匹配的表行根本不会产生输出,显然那不是想要的行为。

regexp_split_to_table 把一个 POSIX 正则表达式模式当作一个定界符来分离一个串。它的语法形式是regexp_split_to_table(string, pattern [, flags ])。如果没有与 pattern 的匹配,该函数返回 string。如果有至少有一个匹配,对每一个匹配它都返回从上一个匹配的末尾(或者串的开头)到这次匹配开头之间的文本。当没有更多匹配时,它返回从上一次匹配的末尾到串末尾之间的文本。flags 参数是一个可选的文本串,它包含零个或更多单字母标志,这些标识可以改变该函数的行为。

regexp_split_to_array 函数的行为和 regexp_split_to_table 相同,不过 regexp_split_to_array 会把它的结果以一个 text 数组的形式返回。它的语法是 regexp_split_to_array(string, pattern [, flags ])。这些参数和 regexp_split_to_table 的相同。

一些例子:

SELECT foo FROM regexp_split_to_table('the quick brown fox jumps over the lazy dog', '\s+') AS foo;
  foo   
-------
 the    
 quick  
 brown  
 fox    
 jumps 
 over   
 the    
 lazy   
 dog    
(9 rows)

SELECT regexp_split_to_array('the quick brown fox jumps over the lazy dog', '\s+');
              regexp_split_to_array             
-----------------------------------------------
 {the,quick,brown,fox,jumps,over,the,lazy,dog}
(1 row)

SELECT foo FROM regexp_split_to_table('the quick brown fox', '\s*') AS foo;
 foo 
-----
 t         
 h         
 e         
 q         
 u         
 i         
 c         
 k         
 b         
 r         
 o         
 w         
 n         
 f         
 o         
 x         
(16 rows)

正如上一个例子所示,正则表达式分离函数会忽略零长度的匹配,这种匹配发生在串的开头或结尾或者正好发生在前一个匹配之后。这和正则表达式匹配的严格定义是相悖的,后者由 regexp_matchregexp_matches 实现,但是通常前者是实际中最常用的行为。其他软件系统如 Perl 也使用相似的定义。

正则表达式细节

AntDB 的正则表达式是使用 Henry Spencer 写的一个包来实现的。下面的正则表达式的大部分描述都是从他的手册页中逐字拷贝过来的。

正则表达式(RE),在 POSIX 1003.2 中定义, 它有两种形式:扩展的 RE 或者是 ERE(大概地说就是那些在 egrep 里的), 基本的 RE 或者是 BRE(大概地说就是那些在 ed 里的)。AntDB 支持两种形式,并且还实现了一些 POSIX 标准中没有但是在类似 Perl 或者 Tcl 这样的语言中得到广泛应用的一些扩展。使用了那些非 POSIX 扩展的 RE 叫高级 RE, 或者本文档里说的ARE。ARE 几乎完全是 ERE 的超集,但是 BRE 有几个符号上的不兼容(以及更多的限制)。首先描述 ARE 和 ERE 形式, 描述那些只适用于 ARE 的特性,然后描述 BRE 的区别是什么。

注意

AntDB 初始时总是推测一个正则表达式遵循 ARE 规则。但是,可以通过为 RE 模式预置一个 embedded option 来选择限制更多的 ERE 或 BRE 规则。这对为期望准确的 POSIX 1003.2 规则的应用提供兼容性很有用。

一个正则表达式被定义为一个或更多分支,它们之间被|分隔。只要能匹配其中一个分支的东西都能匹配正则表达式。

一个分支是一个或多个量化原子或者约束连接而成。一个原子匹配第一个,然后后面的原子匹配第二个, 以此类推;一个空分支匹配空串。

一个量化原子是一个原子, 后面可能跟着一个量词。没有量词的时候,它匹配一个原子, 有量词的时候,它可以匹配若干个原子。

一个约束匹配一个空串,但只是在满足特定条件下才匹配。 约束可以在能够使用原子的地方使用,只是它不能跟着量词。

正则表达式原子

原子描述
(re)(其中 re 是任何正则表达式) 匹配一个对 re 的匹配,匹配将为可能的报告被记下
(?:re)同上,但是匹配不会为了报告而被记下 (一个“非捕获”圆括号集) (只对 ARE)
.匹配任意单个字符
[chars]一个方括号表达式, 匹配 chars 中的任意一个
\k(其中 k 是一个非字母数字字符) 匹配一个被当作普通字符看待的特定字符,例如,\\匹配一个反斜线字符
\c其中 c 是一个字母数字 (可能跟着其它字符),它是一个逃逸(仅对 ARE; 在 ERE 和 BRE 中,它匹配 c
{如果后面跟着一个字符,而不是数字, 那么就匹配左花括弧{;如果跟着一个数字, 那么它是 range 的开始(见下文)
x其中 x 是一个没有其它意义的单个字符,则匹配该字符

RE 不能以反斜线(\)结尾。

注意

如果关掉了 standard_conforming_strings,任何写在文字串常量中的反斜线都需要被双写。

正则表达式量词

量词匹配
*一个由原子的 0 次或更多次匹配组成的序列
+一个由原子的 1 次或更多次匹配组成的序列
?一个由原子的 0 次或 1 次匹配组成的序列
{m}一个由原子的正好 m 次匹配组成的序列
{m,}一个由原子的 m 次或更多次匹配组成的序列
{m,n}一个由原子的从 m 次到 n 次(包括)匹配组成的序列;m 不能超过 n
*?*的非贪婪版本
+?+的非贪婪版本
???的非贪婪版本
{m}?{m}的非贪婪版本
{m,}?{m,}的非贪婪版本
{m,n}?{m,n}的非贪婪版本

使用{...}的形式被称作范围。 一个范围内的数字*m* 和 n 都是无符号十进制整数, 允许的数值从 0 到 255(包含)。

非贪婪的量词(只在 ARE 中可用)匹配对应的正常 (贪婪)模式,区别是它寻找最少的匹配,而不是最多的匹配。

注意

一个量词不能紧跟在另外一个量词后面,例如**是非法的。量词不能作为表达式或者子表达式的开头,也不能跟在^或者|后面。

正则表达式约束

约束描述
^串开头的匹配
$串末尾的匹配
(?=re)在匹配 re 的子串开始的任何点的 positive lookahead 匹配(只对 ARE)
(?!re)在匹配 re 的子串开始的任何点的 negative lookahead 匹配(只对 ARE)
(?<=re)只要有一个点上有一个子串匹配 re 端, positive lookbehind 就在这个点上匹配(只对 ARE)
(?<!re)只要有一个点上没有子串匹配 re 端, negative lookbehind 就在这个点上匹配(只对 ARE)

方括号表达式

方括号表达式是一个包围在[]中的字符列表。它通常匹配列表中的任意单个字符(但见下文)。 如果列表以^开头,它匹配任意单个在该列表参与部分中的字符。如果该列表中两个字符用-隔开, 那它就是那两个字符(包括在内)之间的所有字符范围的缩写,例如,在 ASCII中[0-9]匹配任何十进制数字。两个范围共享一个端点是非法的,例如,a-c-e。范围与字符集关系密切, 可移植的程序应该避免依靠它们。

想在列表中包含文本],可以让它做列表的首字符(如果使用了^,需要放在其后)。 想在列表中包含文本-,可以让它做列表的首字符或者尾字符,或者一个范围的第二个端点。 想在列表中把文本-当做范围的起点, 把它用[..]包围起来,这样它就成为一个排序元素(见下文)。 除了这些字符本身、一些用[的组合(见下段)以及逃逸(只在 ARE 中有效)以外,所有其它特殊字符在方括号表达式里都失去它们的特殊含义。特别是,在 ERE 和 BRE 规则下\不是特殊的,但在 ARE 里,它是特殊的(引入一个逃逸)。

在一个方括号表达式里,一个排序元素(一个字符、一个被当做一个单一字符排序的多字符序列或者一个表示上面两种情况的排序序列名称) 包含在[..]里面的时候表示该排序元素的字符序列。该序列被当做该方括号列表 的一个单一元素。这允许一个包含多字符排序元素的方括号表达式去匹配多于一个字符,例如,如果排序序列包含一个 ch 排序元素, 那么 RE [[.ch.]]*c 匹配 chchcc 的头五个字符。

注意

AntDB 当前不支持多字符排序元素。这些信息描述了将来可能有的行为。

在方括号表达式里,包围在[==]里的排序元素是一个等价类, 代表等效于那一个的所有排序元素的字符序列,包括它本身(如果没有其它等效排序元素,那么就好象封装定界符是[..])。例如,如果 o^ 是一个等价类的成员,那么[[=o=]][[=^=]][o^]都是同义的。一个等价类不能是一个范围的端点。

在方括号表达式里,在[::]里面封装的字符类的名字代表属于该类的所有字符的列表。 字符类不能作为范围的端点使用。POSIX 标准定义了这些字符类的名称: alnum (字符和数字)、alpha (字符)、blank (空格和制表符tab)、cntrl (控制符)、 digit (数位数)、 graph (空格除外可打印字符)、lower (小写字母)、 print (包含空格可打印字符)、 punct (标点符号)、 space (空白)、 upper (大写字母) 和 xdigit (十六进制数)。 对于 7 位 ASCII 字符集中的字符来说,这些标准字符类的行为在不同平台上一般是一致的。一个给定的非 ASCII 字符是否被认为属于这些类别中的一个,取决于正则表达式函数或运算符使用的 collation,或者默认情况下取决于数据库的 LC_CTYPE locale 设置。非 ASCII 字符的分类在不同的平台上会有不同的分类,即使是在类似命名的 locale 中也是如此。(但 C locale 从不认为任何非 ASCII 字符属于上述任何一类)。除了这些标准字符类之外,AntDB 定义了 ascii 字符类,它完全包含 7 位 ASCII 字符集。

方括号表达式里有两个特例:方括号表达式[[:<:]][[:>:]]是约束,分别匹配一个单词开头和结束的空串。 单词定义为一个单词字符序列,前面和后面都没有其它单词字符。单词字符是一个 alnum 字符(和如上所述 POSIX 字符类中定义的一样) 或者一个下划线。这是一个扩展,兼容 POSIX 1003.2, 但那里面并没有说明, 而且在准备移植到其他系统里去的软件里一定要小心使用。通常下文描述的约束逃逸更好些(它们并非更标准,但是更容易键入)。

正则表达式逃逸

逃逸是以\开头,后面跟着一个字母数字字符得特殊序列。 逃逸有好几种变体:字符项、类缩写、约束逃逸以及后引用。在 ARE 里, 如果一个\后面跟着一个字母数字,但是并未组成一个合法的逃逸, 那么它是非法的。在 ERE 中没有逃逸:在方括号表达式之外,一个后面跟着字母数字字符的\只是表示该字符是一个普通的字符,而且在一个方括号表达式里,\是一个普通的字符(后者实际上在 ERE 和 ARE 不兼容)。

字符项逃逸用于便于在 RE 中声明那些不可打印的或其他习惯的字符。

类缩写逃逸用来提供一些常用的字符类缩写。

约束逃逸是一个约束,如果满足特定的条件,它匹配该空串。

后引用\n)匹配数字\n 指定的被前面的圆括号子表达式匹配的同一个串 。例如, ([bc])\1 匹配 bb 或者 cc, 但是不匹配 bc 或者 cb。RE 中子表达式必须完全在后引用前面。子表达式以它们的先导圆括号的顺序编号。非捕获圆括号并不定义子表达式。

正则表达式字符项逃逸

逃逸描述
\a警告(响铃)字符,和 C 中一样
\b退格,和 C 中一样
\B反斜线(\)的同义词,用来减少双写反斜线
\cX(其中 X 是任意字符)低序 5 位和 X 相同的字符,它的其他位都是零
\e排序序列名为 ESC 的字符,如果无法做到该字符为八进制值 033
\f换页,和 C 中一样
\n新行,和 C 中一样
\r回车,和 C 中一样
\t水平制表符,和 C 中一样
\uwxyz(其中 wxyz 正好是四个十六进制位)十六进制值为 0x*wxyz*的字符
\Ustuvwxyz(其中 stuvwxyz 正好是八个十六进制位)十六进制值为 0x*stuvwxyz*的字符
\v垂直制表符,和 C 中一样
\xhhh(其中 hhh 是十六进制位的任意序列)十六进制值为 0xhhh 的字符(一个单一字符,不管用了多少个十六进制位)
\0值为 0(空字节)的字符
\xy(其中 xy 正好是两个八进制位,并且不是一个后引用)八进制值为 0xy 的字符
\xyz(其中 xyz 正好是三个八进制位,并且不是一个后引用)八进制值为 0xyz 的字符

十六进制位是 0-9a-fA-F。八进制位是 0-7

指定 ASCII 范围(0–127)之外的值的数字字符项转义的含义取决于数据库编码。 当编码是 UTF-8 时,转义值等价于 Unicode 代码点,例如 \u1234 表示字符 U+1234。对于其他多字节编码, 字符项转义通常只是指定该字符的字节值的串接。如果该转义值不对应数据库编码中的任何合法字符,将不会发生错误,但是它不会匹配任何数据。

字符项逃逸总是被当作普通字符。例如,\135 是 ASCII 中的], 但 \135 并不终止一个方括号表达式。

正则表达式类缩写逃逸

逃逸描述
\d[[:digit:]]
\s[[:space:]]
\w[[:alnum:]_](注意下划线是被包括的)
\D[^[:digit:]]
\S[^[:space:]]
\W[^[:alnum:]_] (注意下划线是被包括的)

在方括号表达式里,\d\s\w 会失去它们的外层方括号,而 \D\S\W 是非法的(也就是说,例如 [a-c\d] 等效于 [a-c[:digit:]]。同样 [a-c\D] 等效于 [a-c^[:digit:]] 的,也是非法的)。

正则表达式约束逃逸

逃逸描述
\A只在串开头匹配
\m只在一个词的开头匹配
\M只在一个词的末尾匹配
\y只在一个词的开头或末尾匹配
\Y只在一个词的不是开头或末尾的点上匹配
\Z只在串的末尾匹配

一个词被定义成在上面 [[:<:]][[:>:]] 中的声明。在方括号表达式里,约束逃逸是非法的。

正则表达式后引用

逃逸描述
\m(其中 m 是一个非零位)一个到第 m 个子表达式的后引用
\mnn(其中 m 是一个非零位,并且 nn 是一些更多的位,并且十六进制值 mnn 不超过目前能看到的封闭捕获圆括号的数目)一个到第 mnn 个子表达式的后引用

注意

在八进制字符项逃逸和后引用之间有一个历史继承的歧义存在,这个歧义是 通过下面的启发式规则解决的,像上面描述地那样。前导零总是表示这是一个八进制逃逸。而单个非零数字,如果没有跟着任何其它位,那么总是被认为后引用。一个多位的非零开头的序列也被认为是后引用,只要它出现在合适的子表达式后面(也就是说,在后引用的合法范围中的数),否则就被认为是一个八进制。

正则表达式元语法

除了上面描述的主要语法之外,还有几种特殊形式和杂项语法。

如果一个 RE 以***:开头,那么剩下的 RE 都被当作 ARE(这在 AntDB 中通常是无效的,因为 RE 被假定为 ARE,但是如果 ERE 或 BRE 模式通过 flags 参数被指定为一个正则表达式函数时,它确实能产生效果)。如果一个 RE 以***=开头, 那么剩下的 RE 被当作一个文本串,所有的字符都被认为是一个普通字符。

一个 ARE 可以以嵌入选项开头:一个序列(?xyz)(这里的 xyz 是一个或多个字母字符)声明影响剩余 RE 的选项。 这些选项覆盖任何前面判断的选项 — 特别地,它们可以覆盖一个正则表达式操作符隐含的大小写敏感的行为,或者覆盖 flags 参数中的正则表达式函数。可用的选项字母在表 6.24中显示。注意这些同样的选项字母也被用在正则表达式函数的 flags 参数中。

ARE 嵌入选项字母

选项描述
bRE 的剩余部分是一个 BRE
c大小写敏感的匹配(覆盖操作符类型)
eRE 的剩余部分是一个 ERE
i大小写不敏感的匹配(覆盖操作符类型)
mn 的历史原因的同义词
n新行敏感的匹配
p部分新行敏感的匹配
qRE 的剩余部分是一个文字(“quoted”)串,全部是普通字符
s非新行敏感的匹配(默认)
t紧语法(默认,见下文)
w逆部分新行敏感(“怪异”)的匹配
x扩展语法(见下文)

嵌入选项在)终止序列时发生作用。它们只在 ARE 的开始处起作用 (在任何可能存在的***:控制器后面)。

除了通常的()RE 语法(这种情况下所有字符都有效), 还有一种扩展语法,可以通过声明嵌入的 x 选项获得。在扩展语法里,RE 中的空白字符被忽略,就像那些在#和其后的新行(或 RE 的末尾)之间的字符一样。这样就允许给一个复杂的 RE 分段和注释。不过这个基本规则有三种例外:

  • 空白字符或前置了\#将被保留
  • 方括号表达式里的空白或者#将被保留
  • 在多字符符号里面不能出现空白和注释,例如(?:

为了这个目的,空白是空格、制表符、新行和任何属于*空白*字符类的字符。

最后,在 ARE 里,方括号表达式外面,序列(?#ttt)(其中*ttt*是任意不包含一个))的文本)是一个注释, 它被完全忽略。同样,这样的东西是不允许出现在多字符符号的字符中间的,例如 (?:。这种注释更像是一种历史产物而不是一种有用的设施,并且它们的使用已经被废弃;请使用扩展语法来替代。

如果声明了一个初始的***=控制器,那么所有这些元语法扩展都不能使用,因为这样表示把用户输入当作一个文字串而不是 RE 对待。

正则表达式匹配规则

在 RE 可以在给定串中匹配多于一个子串的情况下, RE 匹配串中最靠前的那个子串。如果 RE 可以匹配在那个位置开始的多个子串,要么是取最长的子串,要么是最短的,具体哪种, 取决于 RE 是贪婪的还是非贪婪的。

一个 RE 是否贪婪取决于下面规则:

  • 大多数原子以及所有约束,都没有贪婪属性(因为它们毕竟无法匹配个数变化的文本)。
  • 在一个 RE 周围加上圆括号并不会改变其贪婪性。
  • 带一个固定重复次数量词 ({m}或者{m}?) 的量化原子和原子自身具有同样的贪婪性(可能是没有)。
  • 一个带其他普通的量词(包括{m,n}m 等于 n 的情况)的量化原子是贪婪的(首选最长匹配)。
  • 一个带非贪婪量词(包括{m,n}?中*m*等于 n 的情况)的量化原子是非贪婪的(首选最短匹配)。
  • 一个分支 — 也就是说,一个没有顶级|操作符的 RE — 和它里面的第一个有贪婪属性的量化原子有着同样的贪婪性。
  • 一个由|操作符连接起来的两个或者更多分支组成的 RE 总是贪婪的。

上面的规则所描述的贪婪属性不仅仅适用于独立的量化原子, 而且也适用于包含量化原子的分支和整个 RE。这里的意思是, 匹配是按照分支或者整个 RE 作为一个整体匹配最长或者最短的可能子串。 一旦整个匹配的长度确定,那么匹配任意特定子表达式的部分就基于该子表达式的贪婪属性进行判断,在 RE 里面靠前的子表达式的优先级高于靠后的子表达式。

一个相应的例子:

SELECT SUBSTRING('XY1234Z', 'Y*([0-9]{1,3})');
结果:123
SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
结果:1

在第一个例子里,RE 作为整体是贪婪的,因为Y*是贪婪的。它可以匹配从 Y 开始的东西,并且它匹配从这个位置开始的最长的串, 也就是,Y123。输出是这里的圆括号包围的部分,或者说是 123。在第二个例子里, RE 总体上是一个非贪婪的 RE,因为 Y*? 是非贪婪的。它可以匹配从 Y 开始的最短的子串,也就是说 Y1。子表达式 [0-9]{1,3} 是贪婪的,但是它不能修改总体匹配长度的决定; 因此它被迫只匹配 1

简而言之,如果一个 RE 同时包含贪婪和非贪婪的子表达式,那么总的匹配长度要么是尽可能长,要么是尽可能短,这取决于给整个 RE 赋予的属性。给子表达式赋予的属性只影响在这个匹配里,各个子表达式之间相互允许“吃掉”的多少。

量词{1,1}{1,1}?可以分别用于在一个子表达式 或者整个 RE 上强制贪婪或者非贪婪。当需要整个 RE 具有不同于从其元素中 推导出的贪婪属性时,这很有用。例如,假设尝试将一个包含一些数字的 字符串分隔成数字以及在它们之前和之后的部分,可能会尝试这样做:

SELECT regexp_match('abc01234xyz', '(.*)(\d+)(.*)');
Result: {abc0123,4,xyz}

这不会有用:第一个.*是贪婪的,因此它会“吃掉” 尽可能多的字符而留下\d+去匹配在最后一个可能位置上的最 后一个数字。可能会通过让它变成非贪婪来修复:

SELECT regexp_match('abc01234xyz', '(.*?)(\d+)(.*)');
Result: {abc,0,""}

这也不会有用:因为现在 RE 作为整体来说是非贪婪的,因此它会尽快结束全部的匹配。可以通过强制 RE 整体是贪婪的来得到想要的:

SELECT regexp_match('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}');
Result: {abc,01234,xyz}

独立于 RE 的组件的贪婪性之外控制 RE 的整体贪婪性为处理变长模式提供了 很大的灵活性。

在决定更长或者更短的匹配时,匹配长度是以字符衡量的,而不是排序元素。一个空串会被认为比什么都不匹配长。例如:bb* 匹配abbbc 的中间三个字符;(week|wee)(night|knights)匹配 weeknights 的所有十个字符; 而 (.*).*匹配 abc 的时候,圆括号包围的子表达式匹配所有三个字符;当(a*)*被拿来匹配 bc 时,整个 RE 和圆括号 子表达式都匹配一个空串。

如果声明了大小写无关的匹配,那么效果就好像所有大小写区别在字母表中消失了。如果在多个情况中一个字母以一个普通字符的形式出现在方括号表达式外面,那么它实际上被转换成 一个包含大小写的方括号表达式,也就是说,x 变成 [xX]。 如果它出现在一个方括号表达式里面,那么它的所有大小写的同族都被加入 方括号表达式中,也就是说,x 变成[xX]。当它出现在一个方括号表达式内时,它的所有大小写副本都被加入到方括号表达式中,例如, [x]会变成[xX],而[^x]会变成[^xX]

如果指定了新行敏感的匹配,.和使用^的方括号表达式 将永远不会匹配新行字符(这样,匹配就绝对不会跨越新行,除非 RE 显式地安排了这样的情况)并且^$除了分别匹配串开头和结尾之外,还将分别匹配新行后面和前面的空串。但是 ARE 逃逸\A\Z仍然匹配串的开头和结尾。

如果指定了部分新行敏感的匹配,那么它影响.和方括号表达式, 这个时候和新行敏感的匹配一样,但是不影响^$

如果指定了逆新行敏感匹配,那么它影响^$,其作用和在新行敏感的匹配里一样,但是不影响.和方括号表达式。这个并不是很有用,只是为了满足对称性而提供的。

限制和兼容性

在这个实现里,对 RE 的长度没有特别的限制。但是,那些希望高移植性的程序应该避免使用长度超过 256 字节的 RE,因为 POSIX 兼容 的实现可以拒绝接受这样的 RE。

ARE 实际上和 POSIX ERE 不兼容的唯一的特性是在方括号表达式里\并不失去它特殊的含义。所有其它 ARE 特性都使用在 POSIX ERE 里面是非法或者是未定义、未声明效果的语法;指示器的***就是在 POSIX 的 BRE 和 ERE 之外的语法。

许多 ARE 扩展都是从 Perl 那里借来的(但是有些被做了修改来清理它们),以及一些 Perl 里没有出现的扩展。要注意的不兼容性包括\b\B、对结尾的新行缺乏特别的处理、对那些被新行敏感匹配的东西附加的补齐方括号表达式、在 lookahead/lookbehind 约束里对圆括号和后引用的限制以及最长/最短 匹配(而不是第一匹配)的语义。

AntDB 7.4 之前的版本中识别的 ARE 和 ERE 语法存在两个非常明显的不兼容:

  • 在 ARE 中,后面跟着一个字母数字字符的\要么是一个逃逸要么是一个错误, 但是在以前的版本里,它只是写该字母数字字符的另外一种方法。这个应该不是什么问题, 因为在以前的版本里没有什么理由会写这样的序列。
  • 在 ARE 里,\[]里还是一个特殊字符, 因此在方括号表达式里的一个文本\必须被写成\\

基本正则表达式

BREs 在几个方面和 ERE 不太一样。在 BRE 中,|+?都是普通字符并且没有与它们功能等价的东西。范围的定界符是\{\}, 因为 {}本身是普通字符。嵌套的子表达式的圆括号是\(\),因为()自身是普通字符。除非在 RE 开头或者是圆括号子表达式开头,^都是一个普通字符。 除非在 RE 结尾或者是圆括号子表达式的结尾,$是一个普通字符。如果*出现在 RE 开头或者是圆括号封装的子表达式开头 (前面可能有^),那么它是个普通字符。最后,可以用单数字的后引用,\<\>分别是[[:<:]][[:>:]]的同义词;在 BRE 中没有其它可用的逃逸。

与XQuery的区别 (LIKE_REGEX)

从 SQL:2008 开始,SQL 标准中包含了一个LIKE_REGEX操作符,它根据 XQuery 正则表达式标准执行模式匹配。 AntDB 还没有实现这个操作符,但是可以使用 regexp_match() 函数获得非常类似的行为,因为 XQuery 正则表达式非常接近于上面描述的 ARE 语法。

与现有的基于 POSIX 的正则表达式功能和 XQuery 正则表达式包括。

  • 不支持 XQuery 字符类减法。 这个功能的一个例子是使用下面的例子,只匹配英文辅音。[a-z-[aeiou]]
  • XQuery 字符类速记 c。 不支持 CiI
  • 不支持使用 p{UnicodeProperty}或反过来的 P{UnicodeProperty} 的 XQuery 字符类元素。
  • POSIX 根据当前的 locale 来解释字符类,如/w(可以通过在操作符或函数中附加一个 COLLATE 子句来控制)。 XQuery 通过引用 Unicode 字符属性来指定这些类,因此只有遵循 Unicode 规则的 locale 才能获得等效的行为。
  • SQL 标准(而不是 XQuery 本身)试图满足更多的需求。“newline的变体”比 POSIX 的变体。 上面描述的对新行敏感的匹配选项只考虑 ASCII NL (n) 是新行,但 SQL 会把 CR (r)、CRLF (r/n)(Windows 风格的新行),以及一些 Unicode 唯一的字符,如 LINE SEPARATOR (U+2028) 也视为新行。值得注意的是,.s应该算作一个字符,而不是按照 SQL 的规定算作两个字符。
  • 在中描述的字符输入转义中,XQuery 只支持 nrt
  • XQuery 不支持[::*name*:]]语法,不支持括号表达式中的字符类。
  • XQuery 没有 lookahead 或 lookbehind 约束,也没有任何在。
  • metasyntax 形式在 XQuery 中不存在。
  • 由 XQuery 定义的正则表达式标志字母与 POSIX 的选项字母相关,但不一样。 虽然 iq 选项的行为是一样的,但其他的选项却不一样。
    • XQuery 的 s(允许点匹配换行)和 m(允许^$在换行处匹配)标志提供了与 POSIX 的 n 相同的行为。pw 标志,但它们与POSIX 的 sm 标志的行为不匹配。特别要注意的是,点匹配 -newline 是 POSIX 中的默认行为,但不是 XQuery。
    • XQuery 的 x(忽略模式中的空格)标志与 POSIX 的扩展模式标志明显不同。 POSIX 的 x 标志也允许#在模式中开始注释,并且 POSIX 不会忽略反斜线后的空格字符。

数据类型格式化函数

AntDB 格式化函数提供一套强大的工具用于把各种数据类型 (日期/时间、整数、浮点、数字) 转换成格式化的字符串以及反过来从格式化的字符串转换成 指定的数据类型。这些函数都遵循一个公共的调用规范: 第一个参数是待格式化的值,而第二个是一个定义输出或输入格式的模板。

格式化函数

函数描述例子
to_char ( timestamp, text ) → text``to_char ( timestamp with time zone, text ) → text 根据给定的格式将时间戳转换为字符串。to_char(timestamp '2002-04-20 17:31:12.66', 'HH12:MI:SS')05:31:12
to_char ( interval, text ) → text 根据给定的格式将间隔转换为字符串。to_char(interval '15h 2m 12s', 'HH24:MI:SS')15:02:12
to_char ( numeric_type, text ) → text 根据给定的格式将数字转换为字符串;适用于 integerbigintnumericrealdouble precisionto_char(125, '999')125``to_char(125.8::real, '999D9')125.8``to_char(-125.8, '999D99S')125.80-
to_date ( text, text ) → date 根据给定的格式将字符串转换为日期。to_date('05 Dec 2000', 'DD Mon YYYY')2000-12-05
to_number ( text, text ) → numeric 根据给定的格式将字符串转换为数字。to_number('12,454.8-', '99G999D9S')-12454.8
to_timestamp('05 Dec 2000', 'DD Mon YYYY')2000-12-05 00:00:00-05

提示

to_timestampto_date 存在的目的是为了处理无法用简单造型转换的输入格式。对于大部分标准的日期/时间格式,简单地把源字符串造型成所需的数据类型是可以的,并且简单很多。类似地,对于标准的数字表示形式,to_number 也是没有必要的。

在一个 to_char 输出模板串中,一些特定的模式可以被识别并且被替换成基于给定值的被恰当地格式化的数据。任何不属于模板模式的文本都简单地照字面拷贝。同样,在一个输入 模板串里(对其他函数),模板模式标识由输入数据串提供的值。如果在模板字符串中有不是模板模式的字符,输入数据字符串中的对应字符会被简单地跳过(不管它们是否等于模板字符串字符)。

用于日期/时间格式化的模板模式

模式描述
HH一天中的小时(01–12)
HH12一天中的小时(01–12)
HH24一天中的小时(00–23)
MI分钟(00–59)
SS秒(00–59)
MS毫秒(000–999)
US微秒(000000–999999)
FF1十分之一秒(0–9)
FF2百分之一秒(00–99)
FF3毫秒(000–999)
FF4十分之一毫秒(0000–9999)
FF5百分之一毫秒(00000–99999)
FF6微秒(000000–999999)
SSSS, SSSSS午夜后的秒(0–86399)
AM, am, PM or pm正午指示器(不带句号)
A.M., a.m., P.M. or p.m.正午指示器(带句号)
Y,YYY带逗号的年(4 位或者更多位) with comma
YYYY年(4 位或者更多位)
YYY年的最后 3 位数字
YY年的最后 2 位数字
Y年的最后 1 位数字
IYYYISO 8601 周编号方式的年(4 位或更多位)
IYYISO 8601 周编号方式的年的最后 3 位数字
IYISO 8601 周编号方式的年的最后 2 位数字
IISO 8601 周编号方式的年的最后 1 位数字
BC, bc, ADad纪元指示器(不带句号)
B.C., b.c., A.D.a.d.纪元指示器(带句号)
MONTH全大写形式的月名(空格补齐到 9 字符)
Month全首字母大写形式的月名(空格补齐到 9 字符)
month全小写形式的月名(空格补齐到 9 字符)
MON简写的大写形式的月名(英文 3 字符,本地化长度可变)
Mon简写的首字母大写形式的月名(英文 3 字符,本地化长度可变)
mon简写的小写形式的月名(英文 3 字符,本地化长度可变)
MM月编号 (01–12)
DAY全大写形式的日名(空格补齐到 9 字符)
Day全首字母大写形式的日名(空格补齐到 9 字符)
day全小写形式的日名(空格补齐到 9 字符)
DY简写的大写形式的日名(英语 3 字符,本地化长度可变)
Dy简写的首字母大写形式的日名(英语 3 字符,本地化长度可变)
dy简写的小写形式的日名(英语 3 字符,本地化长度可变)
DDD一年中的日(001–366)
IDDDISO 8601 周编号方式的年中的日 (001–371;年的第 1 日时第一个 ISO 周的周一)
DD月中的日 (01–31)
D周中的日,周日 (1) 到周六 (7
ID周中的 ISO 8601 日,周一 (1) 到周日 (7
W月中的周 (1–5) (第一周从该月的第一天开始)
WW年中的周数 (1–53) (第一周从该年的第一天开始)
IWISO 8601 周编号方式的年中的周数 (01–53;新的一年的第一个周四在第一周)
CC世纪(2 位数)(21 世纪开始于 2001-01-01)
J儒略日(从午夜 UTC 的公元前 4714 年 11 月 24 日开始的整数日数)
Q季度
RM大写形式的罗马计数法的月 (I–XII; I=一月)
rm小写形式的罗马计数法的月 (i–xii; i=一月)
TZ大写形式的时区缩写(仅在 to_char 中支持)
tz小写形式的时区缩写(仅在 to_char 中支持)
TZH时区的小时
TZM时区的分钟
OF从UTC开始的时区偏移(仅在 to_char 中支持)

修饰语可以被应用于模板模式来修改它们的行为。例如,FMMonth 就是带着 FM 修饰语的 Month 模式。

用于日期/时间格式化的模板模式修饰语

修饰语描述例子
FM prefix填充模式(抑制前导零和填充的空格)FMMonth
TH suffix大写形式的序数后缀DDTH, e.g., 12TH
th suffix小写形式的序数后缀DDth, e.g., 12th
FX prefix固定的格式化全局选项(见使用须知)FX Month DD Day
TM prefix翻译模式(基于lc_time]使用本地化的日和月名)TMMonth
SP suffix拼写模式(未实现)DDSP

日期/时间格式化的使用须知:

  • FM 抑制前导的零或尾随的空白, 否则会把它们增加到输入从而把一个模式的输出变成固定宽度。在 AntDB 中,FM 只修改下一个声明,而在 Oracle 中,FM 影响所有随后的声明,并且重复的 FM 修饰语将触发填充模式开和关。

  • 无论是否指定 FMTM 抑制尾随的空格。

  • to_timestampto_date 忽略输入中的字母大小写; 例如 MONMonmon 都接受相同的字符串。 当使用 TM 修饰符时,大小写折叠是根据函数的输入排序规则进行的。

  • to_timestampto_date 跳过了输入字符串开头和日期和时间值周围的多个空格,除非使用了 FX 选项。 例如,to_to_timestamp(' 2000 JUN', 'YYY-MON')to_timestamp('2000 - JUN', 'YYY-MON') 都能工作,但to_timestamp('2000 JUN', 'FXYYYY-MON') 返回一个错误,因为 to_timestamp 只期望一个空格。FX 必须指定为模板中的第一个项目。

  • to_timestampto_date 的模板字符串中的分隔符(一个空格或非字母/非数字字符)与输入字符串中的任何一个分隔符相匹配,或者被跳过,除非使用了 FX 选项。例如,to_to_timestamp('2000JUN', 'YYY///MON')to_timestamp('2000/JUN', 'YYY/MON') 可以工作,但 to_timestamp('2000/JUN', 'YYYY/MON')返回一个错误,因为输入字符串中的分隔符数量超过了模板中的分隔符数量。

    如果指定了 FX,模板字符串中的分隔符正好与输入字符串中的一个字符匹配。 但要注意的是,输入字符串中的字符不需要与模板字符串中的分隔符相同。例如,to_timestamp('2000/JUN', 'FXYYYY MON') 可以工作,但是 to_timestamp('2000/JUN', 'FXYYYY MON') 返回错误,因为模板字符串中的第二个空格会消耗掉输入字符串中的字母 J

  • TZH模板模式可以匹配一个有符号的数字。如果没有FX选项,减号可能是模糊的,可能被解释为分隔符。这种模棱两可的问题可以通过以下方式解决。 如果模板字符串中 TZH 前的分隔符的数量小于输入字符串中减号前的分隔符数量,则减号被解释为 TZH 的一部分。否则,减号被认为是值之间的分隔符。例如,to_timestamp(''2000 -10', 'YYY TZH')-10 匹配,但 to_timestamp('2000 -10', 'YYYY TZH') 匹配 10TZH

  • to_char 模板里可以有普通文本,并且它们会被照字面输出。可以把一个子串放到双引号里强迫它被解释成一个文本,即使它里面包含模板模式也如此。例如,在 '"Hello Year "YYYY' 中,YYYY 将被年份数据代替,但是 Year 中单独的 Y 不会。在 to_dateto_number 以及 to_timestamp 中,文本和双引号字符串会导致跳过该字符串中所包含的字符数量,例如"XX"会跳过两个输入字符(不管它们是不是 XX)。

    提示

    在 AntDB 12之前,可以使用非字母或非数字字符跳过输入字符串中的任意文本。例如,to_timestamp('2000y6m1d', 'yyyyy-MM-DD')以前是有效的。 现在,只能使用字母字符来实现这个目的。 例如,to_timestamp(''2000y6m1d', 'yyyytMMtDDt')to_timestamp('2000y6m1d', 'yyyyy"y"MM"m"DD"d"') 跳过 ymd

  • 如果想在输出里有双引号,那么必须在它们前面放反斜线,例如 '\"YYYY Month\"'。不然,在双引号字符串外面的反斜线就不是特殊的。在双引号字符串内,反斜线会导致下一个字符被取其字面形式,不管它是什么字符(但是这没有特殊效果,除非下一个字符是一个双引号或者另一个反斜线)。

  • to_timestampto_date 中,如果年份格式声明少于四位(如 YYY)并且提供的年份少于四位,年份将被调整为最接近于 2020 年,例如 95 会变成 1995。

  • to_timestampto_date 中,负的年份被视为表示 BC。 如果同时写一个负的年份和一个显式的 BC 字段,又会得到 AD。第 0 年的输入被视为公元前 1 年。

  • to_timestampto_date 中,在处理超过 4 位数的年份时,YYYY 转换具有限制。必须在 YYYY 后面使用一些非数字字符或者模板, 否则年份总是被解释为 4 位数字。例如(对于 20000 年):to_date('200001131', 'YYYYMMDD') 将会被解释成一个 4 位数字的年份,而不是在年份后使用一个非数字分隔符,像 to_date('20000-1131', 'YYYY-MMDD')to_date('20000Nov31', 'YYYYMonDD')

  • to_timestampto_date 中,CC(世纪)字段会被接受,但是如果有 YYYYYYY 或者 Y,YYY 字段则会忽略它。如果 CCYYY 一起使用,则结果被计算为指定世纪中的那一年。如果指定了世纪但是没有指定年,则会假定为该世纪的第一年。

  • to_timestampto_date 中,工作日名称或编号(DAYD 以及相关的字段类型)会被接受,但会为了计算结果的目的而忽略。季度(Q)字段也是一样。

  • to_timestampto_date 中,一个 ISO 8601 周编号的日期(与一个格里高利日期相区别)可以用两种方法之一被指定为 to_timestampto_date

    • 年、周编号和工作日:例如 to_date('2006-42-4', 'IYYY-IW-ID') 返回日期 2006-10-19。如果忽略工作日,它被假定为 1(周一)。
    • 年和一年中的日:例如 to_date('2006-291', 'IYYY-IDDD') 也返回 2006-10-19

    尝试使用一个混合了 ISO 8601 周编号和格里高利日期的域来输入一个日期是无意义的,并且将导致一个错误。在一个 ISO 周编号的年的环境下,一个“月”或“月中的日”的概念没有意义。在一个格里高利年的环境下,ISO 周没有意义。用户应当避免混合格里高利和 ISO 日期声明。

    小心

    虽然 to_date 将会拒绝混合使用格里高利和 ISO 周编号日期的域, to_char 却不会,因为 YYYY-MM-DD (IYYY-IDDD) 这种输出格式也会有用。但是避免写类似 IYYY-MM-DD 的东西,那会得到在起始年附近令人惊讶的结果。

  • to_timestamp 中,毫秒(MS)和微秒(US)域都被用作小数点后的秒位。例如 to_timestamp('12.3', 'SS.MS')不是 3 毫秒, 而是 300,因为该转换把它看做 12 + 0.3 秒。这意味着对于格式 SS.MS 而言,输入值 12.312.3012.300 指定了相同数目的毫秒。要得到三毫秒,必须使用 12.003,转换会把它看做 12 + 0.003 = 12.003 秒。

    下面是一个更复杂的例子∶to_timestamp('15:12:02.020.001230', 'HH24:MI:SS.MS.US')是 15 小时、12 分钟和 2 秒 + 20 毫秒 + 1230微秒 = 2.021230 秒。

  • to_char(..., 'ID') 的一周中日的编号匹配 extract(isodow from ...) 函数,但是 to_char(..., 'D') 不匹配extract(dow from ...) 的日编号。

  • to_char(interval) 格式化 HHHH12 为显示在一个 12 小时的时钟上,即零小时和 36 小时输出为12,而 HH24 会输出完整的小时值,对于间隔它可以超过 23.

用于数字格式化的模板模式

模式描述
9数位(如果无意义可以被删除)
0数位(即便没有意义也不会被删除)
. (period)小数点
, (comma)分组(千)分隔符
PR尖括号内的负值
S带符号的数字(使用区域)
L货币符号(使用区域)
D小数点(使用区域)
G分组分隔符(使用区域)
MI在指定位置的负号(如果数字 < 0)
PL在指定位置的正号(如果数字 > 0)
SG在指定位置的正/负号
RN罗马数字(输入在 1 和 3999 之间)
TH or th序数后缀
V移动指定位数(参阅注解)
EEEE科学记数的指数

数字格式化的用法须知:

  • 0 指定一个总是被打印的数位,即便它包含前导/拖尾的零。9 也指定一个数位,但是如果它是前导零则会被空格替换,而如果是拖尾零并且指定了填充模式则它会被删除(对于 to_number() 来说,这两种模式字符等效)。
  • 模式字符 SLD 以及G 表示当前 locale 定义的负号、货币符号、小数点以及数字分隔符字符(见 lc_monetary 和 lc_numeric)。不管 locale 是什么,模式字符句号和逗号就表示小数点和数字分隔符。
  • 对于 to_char() 的模式中的一个负号,如果没有明确的规定,将为该负号保留一列,并且它将被锚接到(出现在左边)那个数字。如果 S 正好出现在某个 9 的左边,它也将被锚接到那个数字。
  • 使用 SGPLMI 格式化的符号并不挂在数字上面; 例如,to_char(-12, 'MI9999') 生成'- 12',而 to_char(-12, 'S9999') 生成 ' -12'。(Oracle 里的实现不允许在 9 前面使用 MI,而是要求 9MI 前面。)
  • TH 不会转换小于零的数值,也不会转换小数。
  • PLSGTH 是 AntDB 扩展。
  • to_number 中,如果没有使用 LTH 之类的非数据模板模式,相应数量的输入字符会被跳过,不管它们是否匹配模板模式,除非它们是数据字符(也就是数位、负号、小数点或者逗号)。例如,TH 会跳过两个非数据字符。
  • 带有 to_charV 会把输入值乘上 10^*n*,其中 n 是跟在 V 后面的位数。带有 to_numberV 以类似的方式做除法。to_charto_number 不支持使用结合小数点的 V(例如,不允许 99.9V99)。
  • EEEE(科学记数法)不能和任何其他格式化模式或修饰语(数字和小数点模式除外)组合在一起使用,并且必须位于格式化字符串的最后(例如 9.99EEEE 是一个合法的模式)。

某些修饰语可以被应用到任何模板来改变其行为。例如,FM99.99 是带有 FM 修饰语的 99.99 模式。表 6.29中展示了用于数字格式化模式修饰语。

用于数字格式化的模板模式修饰语

修饰语描述例子
FM prefix填充模式(抑制拖尾零和填充的空白)FM99.99
TH suffix大写序数后缀999TH
th suffix小写序数后缀999th

展示了一些使用 to_char 函数的例子。

to_char 例子

表达式结果
to_char(current_timestamp, 'Day, DD HH12:MI:SS')'Tuesday , 06 05:39:18'
to_char(current_timestamp, 'FMDay, FMDD HH12:MI:SS')'Tuesday, 6 05:39:18'
to_char(-0.1, '99.99')' -.10'
to_char(-0.1, 'FM9.99')'-.1'
to_char(-0.1, 'FM90.99')'-0.1'
to_char(0.1, '0.9')' 0.1'
to_char(12, '9990999.9')' 0012.0'
to_char(12, 'FM9990999.9')'0012.'
to_char(485, '999')' 485'
to_char(-485, '999')'-485'
to_char(485, '9 9 9')' 4 8 5'
to_char(1485, '9,999')' 1,485'
to_char(1485, '9G999')' 1 485'
to_char(148.5, '999.999')' 148.500'
to_char(148.5, 'FM999.999')'148.5'
to_char(148.5, 'FM999.990')'148.500'
to_char(148.5, '999D999')' 148,500'
to_char(3148.5, '9G999D999')' 3 148,500'
to_char(-485, '999S')'485-'
to_char(-485, '999MI')'485-'
to_char(485, '999MI')'485 '
to_char(485, 'FM999MI')'485'
to_char(485, 'PL999')'+485'
to_char(485, 'SG999')'+485'
to_char(-485, 'SG999')'-485'
to_char(-485, '9SG99')'4-85'
to_char(-485, '999PR')'<485>'
to_char(485, 'L999')'DM 485'
to_char(485, 'RN')' CDLXXXV'
to_char(485, 'FMRN')'CDLXXXV'
to_char(5.2, 'FMRN')'V'
to_char(482, '999th')' 482nd'
to_char(485, '"Good number:"999')'Good number: 485'
to_char(485.8, '"Pre:"999" Post:" .999')'Pre: 485 Post: .800'
to_char(12, '99V999')' 12000'
to_char(12.4, '99V999')' 12400'
to_char(12.45, '99V9')' 125'
to_char(0.0004859, '9.99EEEE')' 4.86e-04'

时间/日期函数和操作符

所有下文描述的接受 timetimestamp 输入的函数和操作符实际上都有两种变体: 一种接收 time with time zonetimestamp with time zone, 另外一种接受 time without time zone 或者 timestamp without time zone。为了简化,这些变种没有被独立地展示。此外,+*操作符都是可交换的操作符对(例如,date + integer 和 integer + date);只显示其中一个。

日期/时间操作符

操作符描述例子
date + integerdate 给日期加上天数 date '2001-09-28' + 72001-10-05
date + intervaltimestamp 为日期添加时间间隔 date '2001-09-28' + interval '1 hour'2001-09-28 01:00:00
date + timetimestamp 在日期中添加一天中的时间 date '2001-09-28' + time '03:00'2001-09-28 03:00:00
interval + intervalinterval 添加时间间隔 interval '1 day' + interval '1 hour'1 day 01:00:00
timestamp + intervaltimestamp 在时间戳中添加一个时间间隔 timestamp '2001-09-28 01:00' + interval '23 hours'2001-09-29 00:00:00
time + intervaltime 为时间添加时间间隔 time '01:00' + interval '3 hours'04:00:00
- intervalinterval 取否一个时间间隔 - interval '23 hours'-23:00:00
date - dateinteger 减去日期,生成经过的天数 date '2001-10-01' - date '2001-09-28'3
date - integerdate 从日期中减去天数 date '2001-10-01' - 72001-09-24
date - intervaltimestamp 从日期中减去时间间隔 date '2001-09-28' - interval '1 hour'2001-09-27 23:00:00
time - timeinterval 减去时间 time '05:00' - time '03:00'02:00:00
time - intervaltime 从时间中减去时间间隔 time '05:00' - interval '2 hours'03:00:00
timestamp - intervaltimestamp 从时间戳中减去时间间隔 timestamp '2001-09-28 23:00' - interval '23 hours'2001-09-28 00:00:00
interval - intervalinterval 减去时间间隔 interval '1 day' - interval '1 hour'1 day -01:00:00
timestamp - timestampinterval 减去时间戳(将24小时间隔转换为天,类似于justify_hours()timestamp '2001-09-29 03:00' - timestamp '2001-07-27 12:00'63 days 15:00:00
interval * double precisioninterval 将时间间隔乘以数量 interval '1 second' * 90000:15:00``interval '1 day' * 2121 days``interval '1 hour' * 3.503:30:00
interval / double precisioninterval 用时间间隔除以数量 interval '1 hour' / 1.500:40:00

日期/时间函数

函数描述例子
age ( timestamp, timestamp ) → interval 减去参数,生成一个使用年和月,而不是只用日的“符号化”的结果 age(timestamp '2001-04-10', timestamp '1957-06-13')43 years 9 mons 27 days
age ( timestamp ) → intervalcurrent_date 减去参数(在午夜)age(timestamp '1957-06-13')62 years 6 mons 10 days
clock_timestamp ( ) → timestamp with time zone 当前日期和时间(在语句执行期间变化);clock_timestamp()2019-12-23 14:39:53.662522-05
current_datedate 当前日期;current_date2019-12-23
current_timetime with time zone 一天中的当前时间;current_time14:39:53.662522-05
current_time ( integer ) → time with time zone 一天中的当前时间;有限精度;current_time(2)14:39:53.66-05
current_timestamptimestamp with time zone 当前日期和时间(当前事务的开始);current_timestamp2019-12-23 14:39:53.662522-05
current_timestamp ( integer ) → timestamp with time zone 当前日期和时间(当前事务的开始);有限精度;参见current_timestamp(0)2019-12-23 14:39:53-05
date_part ( text, timestamp ) → double precision 获取时间戳字段(等同于 extract);date_part('hour', timestamp '2001-02-16 20:38:40')20
date_part ( text, interval ) → double precision 获取时间间隔子字段(等同于 extract);date_part('month', interval '2 years 3 months')3
date_trunc ( text, timestamp ) → timestamp 截断到指定的精度;date_trunc('hour', timestamp '2001-02-16 20:38:40')2001-02-16 20:00:00
date_trunc ( text, timestamp with time zone, text ) → timestamp with time zone 在规定的时区中截断到指定的精度;date_trunc('day', timestamptz '2001-02-16 20:38:40+00', 'Australia/Sydney')2001-02-16 13:00:00+00
date_trunc ( text, interval ) → interval 截断到指定的精度;date_trunc('hour', interval '2 days 3 hours 40 minutes')2 days 03:00:00
extract ( field from timestamp ) → double precision 获取时间戳子字段;extract(hour from timestamp '2001-02-16 20:38:40')20
extract ( field from interval ) → double precision 获取时间间隔子字段;extract(month from interval '2 years 3 months')3
isfinite ( date ) → boolean 测试有限日期(不是+/-无限)isfinite(date '2001-02-16')true
isfinite ( timestamp ) → boolean 测试有限时间戳(不是+/-无限)isfinite(timestamp 'infinity')false
isfinite ( interval ) → boolean 测试有限时间间隔 (当前总是为真)isfinite(interval '4 hours')true
justify_days ( interval ) → interval 调整间隔,使得30天时间周期表示为月 justify_days(interval '35 days')1 mon 5 days
justify_hours ( interval ) → interval 调整时间间隔,使得24小时时间周期表示为日 justify_hours(interval '27 hours')1 day 03:00:00
justify_interval ( interval ) → interval 使用 justify_daysjustify_hours 调整时间间隔; 通过额外的符号调整 justify_interval(interval '1 mon -1 hour')29 days 23:00:00
localtimetime 一天中当前时间;localtime14:39:53.662522
localtime ( integer ) → time 一天中的当前时间,有限精度;localtime(0)14:39:53
localtimestamptimestamp 当前日期和时间(当前事务的开始);localtimestamp2019-12-23 14:39:53.662522
localtimestamp ( integer ) → timestamp 当前日期和时间(当前事务的开始);有限精度;localtimestamp(2)2019-12-23 14:39:53.66
make_date ( year int, month int, day int ) → date 从年、月和日字段创建日期 make_date(2013, 7, 15)2013-07-15
make_interval ( [ years int [, months int [, weeks int [, days int [, hours int [, mins int [, secs double precision ]]]]]]] ) → interval 从年、月、周、日、小时、分钟和秒字段创建时间间隔,每个字段默认为 0 make_interval(days => 10)10 days
make_time ( hour int, min int, sec double precision ) → time 从小时、分钟和秒字段创建时间 make_time(8, 15, 23.5)08:15:23.5
make_timestamp ( year int, month int, day int, hour int, min int, sec double precision ) → timestamp 从年、月、日、小时、分钟和秒字段创建时间戳 make_timestamp(2013, 7, 15, 8, 15, 23.5)2013-07-15 08:15:23.5
make_timestamptz ( year int, month int, day int, hour int, min int, sec double precision [, timezone text ] ) → timestamp with time zone 从年,月,日,小时,分钟和秒字段结合时区创建时间戳;如果没有指定 timezone,则使用当前时区 make_timestamptz(2013, 7, 15, 8, 15, 23.5)2013-07-15 08:15:23.5+01
now ( ) → timestamp with time zone 当前日期和时间(当前事务的开始);now()2019-12-23 14:39:53.662522-05
statement_timestamp ( ) → timestamp with time zone 当前日期和时间(当前语句的开始);statement_timestamp()2019-12-23 14:39:53.662522-05
timeofday ( ) → text 当前的日期和时间(类似 clock_timestamp,但是采用 text 字符串);timeofday()Mon Dec 23 14:39:53.662522 2019 EST
transaction_timestamp ( ) → timestamp with time zone 当前日期和时间(当前事务的开始);transaction_timestamp()2019-12-23 14:39:53.662522-05
to_timestamp ( double precision ) → timestamp with time zone 将 Unix 纪元转换为带时区的时间戳(从 1970-01-01 00:00:00+00 开的秒)to_timestamp(1284352323)2010-09-13 04:32:03+00

除了这些函数以外,还支持 SQL 操作符 OVERLAPS

(start1, end1) OVERLAPS (start2, end2)
(start1, length1) OVERLAPS (start2, length2)

这个表达式在两个时间域(用它们的端点定义)重叠的时候得到真,当它们不重叠时得到假。端点可以用一对日期、时间或者时间戳来指定;或者是用一个后面跟着一个间隔的日期、时间或时间戳来指定。当一对值被提供时,起点或终点都可以被写在前面,OVERLAPS 会自动地把较早的值作为起点。每一个时间段被认为是表示半开的间隔 start <= time < end,除非 startend 相等,这种情况下它表示单个时间实例。例如这表示两个只有一个共同端点的时间段不重叠。

SELECT (DATE '2001-02-16', DATE '2001-12-21') OVERLAPS
       (DATE '2001-10-30', DATE '2002-10-30');
结果:true
SELECT (DATE '2001-02-16', INTERVAL '100 days') OVERLAPS
       (DATE '2001-10-30', DATE '2002-10-30');
结果:false
SELECT (DATE '2001-10-29', DATE '2001-10-30') OVERLAPS
       (DATE '2001-10-30', DATE '2001-10-31');
结果:false
SELECT (DATE '2001-10-30', DATE '2001-10-30') OVERLAPS
       (DATE '2001-10-30', DATE '2001-10-31');
结果:true

当把一个 interval 值添加到 timestamp with time zone 上(或从中减去)时, 天的部分会按照指定的天数增加或减少 timestamp with time zone 的日期,保持一天中相同的时间。 对于横跨夏令时的变化(当会话的时区被设置为可识别 DST 的时区时),这意味着interval '1 day' 并 不一定等于 interval '24 hours'。 例如,当会话的时区设置为 America/Denver 时:

SELECT timestamp with time zone '2005-04-02 12:00:00-07' + interval '1 day';
Result: 2005-04-03 12:00:00-06
SELECT timestamp with time zone '2005-04-02 12:00:00-07' + interval '24 hours';
Result: 2005-04-03 13:00:00-06

发生此情况是因为夏令时在 America/Denver 时区的 2005-04-03 02:00:00 的时间发生更改而跳过了一个小时。

注意 age 返回的月数域可能有歧义,因为不同的月份有不同的天数。 AntDB 的方法是当计算部分月数时,采用两个日期中较早的月。例如:age('2004-06-01', '2004-04-30')使用 4 月份得到 1 mon 1 day,而用 5 月分时会得到 1 mon 2 days,因为 5 月有 31 天,而 4 月只有 30 天。

日期和时间戳的减法也可能会很复杂。执行减法的一种概念上很简单的方法是,使用 EXTRACT(EPOCH FROM ...)把每个值都转换成秒数,然后执行减法, 这样会得到两个值之间的数。这种方法将会适应每个月中天数、 时区改变和夏令时调整。使用“-”操作符的日期或时间 戳减法会返回值之间的天数(24 小时)以及时/分/秒,也会做同样的调整。 age 函数会返回年、月、日以及时/分/秒,执行按域的减法,然后对 负值域进行调整。下面的查询展示了这些方法的不同。例子中的结果由 timezone = 'US/Eastern' 产生,这使得两个使用的日期之间存在着夏令 时的变化:

SELECT EXTRACT(EPOCH FROM timestamptz '2013-07-01 12:00:00') -
       EXTRACT(EPOCH FROM timestamptz '2013-03-01 12:00:00');
Result: 10537200
SELECT (EXTRACT(EPOCH FROM timestamptz '2013-07-01 12:00:00') -
        EXTRACT(EPOCH FROM timestamptz '2013-03-01 12:00:00'))
        / 60 / 60 / 24;
Result: 121.958333333333
SELECT timestamptz '2013-07-01 12:00:00' - timestamptz '2013-03-01 12:00:00';
Result: 121 days 23:00:00
SELECT age(timestamptz '2013-07-01 12:00:00', timestamptz '2013-03-01 12:00:00');
Result: 4 mons

EXTRACT, date_part

EXTRACT(field FROM source)

extract 函数从日期/时间值中抽取子域,例如年或者小时等。source 必须是一个类型 timestamptimeinterval 的值表达式(类型为 date 的表达式将被造型为 timestamp,并且因此也可以被同样使用)。field 是一个标识符或者字符串,它指定从源值中抽取的域。extract 函数返回类型为 double precision 的值。 下列值是有效的域名字∶

  • century

    世纪 SELECT EXTRACT(CENTURY FROM TIMESTAMP '2000-12-16 12:21:13'); *结果:*20 SELECT EXTRACT(CENTURY FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*21 第一个世纪从 0001-01-01 00:00:00 AD 开始, 尽管那时候人们还不知道这是第一个世纪。这个定义适用于所有使用格里高利历法的国家。其中没有 0 世纪,直接从公元前 1 世纪到公元 1 世纪。 如果认为这个不合理,那么请把抱怨发给:罗马圣彼得教堂,梵蒂冈,教皇收。

  • day

    对于 timestamp 值,是(月份)里的日域(1–31);对于 interval 值,是日数 SELECT EXTRACT(DAY FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*16 SELECT EXTRACT(DAY FROM INTERVAL '40 days 1 minute'); *结果:*40

  • decade

    年份域除以 10 SELECT EXTRACT(DECADE FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*200

  • dow

    一周中的日,从周日(0)到周六(6SELECT EXTRACT(DOW FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*5请注意,extract 的一周中的日和 to_char(..., 'D') 函数不同。

  • doy

    一年的第几天(1–365/366)SELECT EXTRACT(DOY FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*47

  • epoch

    对于 timestamp with time zone 值, 是自 1970-01-01 00:00:00 UTC 以来的秒数(结果可能是负数); 对于 date and timestamp 值,是自本地时间 1970-01-01 00:00:00 以来的描述;对于 interval 值,它是时间间隔的总秒数。SELECT EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40.12-08'); *结果:*982384720.12 SELECT EXTRACT(EPOCH FROM INTERVAL '5 days 3 hours'); *结果:*442800 不能用 to_timestamp 把一个 epoch 值转换回成时间戳:SELECT to_timestamp(982384720.12); *Result:* 2001-02-17 04:38:40.12+00

  • hour

    小时域(0–23)SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*20

  • isodow

    一周中的日,从周一(1)到周日(7SELECT EXTRACT(ISODOW FROM TIMESTAMP '2001-02-18 20:38:40'); *结果:*7 除了周日,这和 dow 相同。这符合 ISO 8601 中一周中的日的编号。

  • isoyear

    日期所落在的 ISO 8601 周编号的年(不适用于间隔)SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-01'); *结果:*2005 SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-02'); *结果:*2006每一个 ISO 8601 周编号的年都开始于包含 1 月 4 日的那一周的周一,在早的 1 月或迟的 12 月中 ISO 年可能和格里高利年不同。更多信息见 week 域。这个域不能用于 AntDB 8.3 之前的版本。

  • microseconds

    秒域,包括小数部分,乘以 1,000,000。请注意它包括全部的秒 SELECT EXTRACT(MICROSECONDS FROM TIME '17:12:28.5'); *结果:*28500000

  • millennium

    千年 SELECT EXTRACT(MILLENNIUM FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*319xx 的年份在第二个千年里。第三个千年从 2001 年 1 月 1 日开始。

  • milliseconds

    秒域,包括小数部分,乘以 1000。请注意它包括完整的秒。SELECT EXTRACT(MILLISECONDS FROM TIME '17:12:28.5'); *结果:*28500

  • minute

    分钟域(0–59)SELECT EXTRACT(MINUTE FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*38

  • month

    对于 timestamp 值,它是一年里的月份数(1–12); 对于 interval 值,它是月的数目,然后对 12 取模(0–11)SELECT EXTRACT(MONTH FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*2 SELECT EXTRACT(MONTH FROM INTERVAL '2 years 3 months'); *结果:*3 SELECT EXTRACT(MONTH FROM INTERVAL '2 years 13 months'); *结果:*1

  • quarter

    该天所在的该年的季度(1–4)SELECT EXTRACT(QUARTER FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*1

  • second

    秒字段,包括任何小数秒。SELECT EXTRACT(SECOND FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*40 SELECT EXTRACT(SECOND FROM TIME '17:12:28.5'); *结果:*28.5

  • timezone

    与 UTC 的时区偏移,以秒记。正数对应 UTC 东边的时区,负数对应 UTC 西边的时区(从技术上来看,AntDB 不使用 UTC,因为其中不处理闰秒)。

  • timezone_hour

    时区偏移的小时部分。

  • timezone_minute

    时区偏移的分钟部分。

  • week

    该天在所在的 ISO 8601 周编号的年份里是第几周。根据定义, 一年的第一周包含该年的 1月 4 日并且 ISO 周从星期一开始。换句话说,一年的第一个星期四在第一周。在 ISO 周编号系统中,早的 1 月的日期可能位于前一年的第五十二或者第五十三周,而迟的 12 月的日期可能位于下一年的第一周。例如, 2005-01-01位于 2004 年的第五十三周,并且 2006-01-01 位于 2005 年的第五十二周,而 2012-12-31 位于 2013 年的第一周。推荐把 isoyear 域和 week 一起使用来得到一致的结果。SELECT EXTRACT(WEEK FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*7

  • year

    年份域。要记住这里没有 0 AD,所以从 AD 年里抽取 BC 年应该小心处理。SELECT EXTRACT(YEAR FROM TIMESTAMP '2001-02-16 20:38:40'); *结果:*2001

注意

当输入值为 +/-Infinity 时,extract 对于单调增的域(epochjulianyearisoyeardecadecentury 以及 millennium)返回 +/-Infinity。对于其他域返回 NULL。AntDB 9.6 之前的版本对所有输入无穷的情况都返回零。

extract 函数主要的用途是做计算性处理。对于用于显示的日期/时间值格式化。

在传统的 Ingres 上建模的 date_part 函数等价于 SQL 标准函数 extract

date_part('field', source)

请注意这里的 field 参数必须是一个串值,而不是一个名字。有效的 date_part 域名和 extract 相同。

SELECT date_part('day', TIMESTAMP '2001-02-16 20:38:40');
结果:16

SELECT date_part('hour', INTERVAL '4 hours 3 minutes');
结果:4

date_trunc

date_trunc 函数在概念上和用于数字的 trunc 函数类似。

date_trunc(field, source [, time_zone ])

source 是类型 timestampinterval 的值表达式(类型 datetime 的值都分别被自动转换成 timestamptimestamp with time zone 或者 interval)。field 选择对输入值选用什么样的精度进行截断。返回的值是 timestamp, timestamp with time zone 类型或者所有小于选定的精度的域都设置为零(或者一,对于日期和月份)的 interval

field 的有效值是∶

microseconds
milliseconds
second
minute
hour
day
week
month
quarter
year
decade
century
millennium

当输入值的类型为 timestamp with time zone 时。截断是针对特定时区进行的。 例如,截断为 day,产生的值是 是该区域的午夜。 默认情况下,截断是在以下方面进行的 到当前的 TimeZone 设置,但在当前的 可以提供可选的 time_zone 参数。以指定不同的时区。

当处理 timestamp without time zoneinterval 输入时,不能指定时区。 这些总是按表面值来处理。

示例(假设当地时区为 America/New_York):

SELECT date_trunc('hour', TIMESTAMP '2001-02-16 20:38:40');
结果:2001-02-16 20:00:00

SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40');
结果:2001-01-01 00:00:00

SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40+00');
Result: 2001-02-16 00:00:00-05

SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40+00', 'Australia/Sydney');
Result: 2001-02-16 08:00:00-05

SELECT date_trunc('hour', INTERVAL '3 days 02:47:33');
Result: 3 days 02:00:00

AT TIME ZONE

AT TIME ZONE 把时间戳 without 时区转换成时间戳 with 时区或者反过来,并且把 time with time zone 值转换成不同的时区。

AT TIME ZONE 变体

操作符描述例子
timestamp without time zone AT TIME ZONE zonetimestamp with time zone 将给定的时间戳 without 时区转换为时间戳 with 时区,假设给定的值在指定的时区内。timestamp '2001-02-16 20:38:40' at time zone 'America/Denver'2001-02-17 03:38:40+00
timestamp with time zone AT TIME ZONE zonetimestamp without time zone将给定的时间戳 with 时区转换为时间戳 without 时区,因为时间将出现在该时区中 timestamp with time zone '2001-02-16 20:38:40-05' at time zone 'America/Denver'2001-02-16 18:38:40
time with time zone AT TIME ZONE zonetime with time zone 将给定的时间with时区转换为新的时区。由于没有提供日期,这将使用指定目的区域的当前活动 UTC 偏移量。time with time zone '05:34:17-05' at time zone 'UTC'10:34:17+00

在这些表达式里,需要的时区 zone 可以指定为文本值(例如,'America/Los_Angeles')或者一个间隔 (例如,INTERVAL '-08:00')。 在文本情况下,可用的时区名字可以用第 8.5.3 节中描述的任何方式指定。 时间区间只适用于与 UTC 有固定偏移量的区域,因此在实践中并不常见。

例子 (假设当前 TimeZone 设置为 America/Los_Angeles):

SELECT TIMESTAMP '2001-02-16 20:38:40' AT TIME ZONE 'America/Denver';
Result: 2001-02-16 19:38:40-08

SELECT TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT TIME ZONE 'America/Denver';
Result: 2001-02-16 18:38:40

SELECT TIMESTAMP '2001-02-16 20:38:40' AT TIME ZONE 'Asia/Tokyo' AT TIME ZONE 'America/Chicago';
Result: 2001-02-16 05:38:40

第一个例子给缺少时区的值加上了时区,并且显示了使用当前 TimeZone 设置的值。 第二个例子把带有时区值的时间戳移动到指定的时区,并且返回不带时区的值。 这允许存储和显示不同于当前 TimeZone 设置的值。第三个例子把东京时间转换成芝加哥时间。

函数 timezone(*zone*, *timestamp*) 等效于 SQL 兼容的结构*timestamp* AT TIME ZONE *zone*

当前日期/时间

AntDB 提供了许多返回当前日期和时间的函数。这些 SQL 标准的函数全部都按照当前事务的开始时刻返回值:

CURRENT_DATE
CURRENT_TIME
CURRENT_TIMESTAMP
CURRENT_TIME(precision)
CURRENT_TIMESTAMP(precision)
LOCALTIME
LOCALTIMESTAMP
LOCALTIME(precision)
LOCALTIMESTAMP(precision)

CURRENT_TIMECURRENT_TIMESTAMP 传递带有时区的值;LOCALTIMELOCALTIMESTAMP 传递的值不带时区。

CURRENT_TIMECURRENT_TIMESTAMPLOCALTIMELOCALTIMESTAMP 可以有选择地接受一个精度参数,该精度导致结果的秒域被园整为指定小数位。如果没有精度参数,结果将被给予所能得到的全部精度。

一些例子:

SELECT CURRENT_TIME;
结果: 14:39:53.662522-05

SELECT CURRENT_DATE;
结果: 2019-12-23

SELECT CURRENT_TIMESTAMP;
结果: 2019-12-23 14:39:53.662522-05

SELECT CURRENT_TIMESTAMP(2);
结果: 2019-12-23 14:39:53.66-05

SELECT LOCALTIMESTAMP;
结果: 2019-12-23 14:39:53.662522

因为这些函数全部都按照当前事务的开始时刻返回结果,所以它们的值在事务运行的整个期间内都不改变。 认为这是一个特性:目的是为了允许一个事务在“当前”时间上有一致的概念, 这样在同一个事务里的多个修改可以保持同样的时间戳。

注意

许多其它数据库系统可能会更频繁地推进这些值。

AntDB 同样也提供了返回当前语句开始时间的函数, 它们会返回函数被调用时的真实当前时间。这些非 SQL 标准的函数列表如下:

transaction_timestamp()
statement_timestamp()
clock_timestamp()
timeofday()
now()

transaction_timestamp() 等价于 CURRENT_TIMESTAMP,但是其命名清楚地反映了它的返回值。statement_timestamp() 返回当前语句的开始时刻(更准确的说是收到 客户端最后一条命令的时间)。statement_timestamp()transaction_timestamp() 在一个事务的第一条命令期间返回值相同,但是在随后的命令中却不一定相同。 clock_timestamp() 返回真正的当前时间,因此它的值甚至在同一条 SQL 命令中都会变化。timeofday() 是一个有历史原因的 AntDB 函数。和 clock_timestamp() 相似,timeofday() 也返回真实的当前时间,但是它的结果是一个格式化的 text 串,而不是 timestamp with time zone 值。now() 是 AntDB 的一个传统,等效于 transaction_timestamp()

所有日期/时间类型还接受特殊的文字值 now,用于指定当前的日期和时间(重申,被解释为当前事务的开始时刻)。因此,下面三个都返回相同的结果:

SELECT CURRENT_TIMESTAMP;
SELECT now();
SELECT TIMESTAMP 'now';  -- 但请参阅下面的提示

提示

当指定以后要计算的值时,不要使用第三种形式,例如在表列的 DEFAULT 子句中。 系统将在分析这个常量的时候把 now 转换为一个 timestamp, 这样需要默认值时就会得到创建表的时间。而前两种形式要到实际使用缺省值的时候才被计算, 因为它们是函数调用。因此它们可以给出每次插入行的时刻。

延时执行

下面的这些函数可以用于让服务器进程延时执行:

pg_sleep ( double precision )
pg_sleep_for ( interval )
pg_sleep_until ( timestamp with time zone )

pg_sleep 使当前会话的进程休眠,直到过去给定的秒数。可以指定几分之一秒的延迟。 pg_sleep_for 是一个方便的函数,允许将睡眠时间指定为时间间隔。 pg_sleep_until 是一个方便的函数,用于需要特定的唤醒时间。例如:

SELECT pg_sleep(1.5);
SELECT pg_sleep_for('5 minutes');
SELECT pg_sleep_until('tomorrow 03:00');

注意

有效的休眠时间间隔精度是平台相关的,通常 0.01 秒是通用值。休眠延迟将至少持续指 定的时长,也有可能由于服务器负荷而比指定的时间长。特别地, pg_sleep_until 并不保证能刚好在指定的时刻被唤醒,但它不会 在比指定时刻早的时候醒来。

警告

请确保在调用 pg_sleep 或者其变体时,会话没有持有不必要 的锁。否则其它会话可能必须等待休眠会话,因而减慢整个系统速度。

枚举支持函数

对于枚举类型, 有一些函数允许更清洁的编码,而不需要为一个枚举类型硬写特定的值。本例假定一个枚举类型被创建为:

CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');

枚举支持函数

函数描述例子
enum_first ( anyenum ) → anyenum 返回输入枚举类型的第一个值。enum_first(null::rainbow)red
enum_last ( anyenum ) → anyenum 返回输入枚举类型的最后一个值。enum_last(null::rainbow)purple
enum_range ( anyenum ) → anyarray 将输入枚举类型的所有值作为一个有序的数组返回。enum_range(null::rainbow){red,orange,yellow,green,blue,purple}
enum_range ( anyenum, anyenum ) → anyarray 以一个数组返回在给定两个枚举值之间的范围。值必须来自相同的枚举类型。 如果第一个参数为空,其结果将从枚举类型的第一个值开始。如果第二参数为空,其结果将以枚举类型的最后一个值结束。enum_range('orange'::rainbow, 'green'::rainbow){orange,yellow,green}``enum_range(NULL, 'green'::rainbow){red,orange,yellow,green}``enum_range('orange'::rainbow, NULL){orange,yellow,green,blue,purple}

请注意,除了双参数形式的 enum_range 外, 这些函数忽略传递给它们的具体值,它们只关心声明的数据类型。 空值或类型的一个特定值可以通过,并得到相同的结果。这些函数更多地被用于一个表列或函数参数,而不是一个硬写的类型名,如例子中所使用。

几何函数和操作符

几何类型 pointboxlseglinepathpolygoncircle 有一大堆本地支持函数和操作符。

几何操作符

操作符描述例子
geometric_type + point*geometric_type* 将第二个 point 的坐标添加到第一个参数的每个点的坐标中,从而执行翻译。 适用于 pointboxpathcirclebox '(1,1),(0,0)' + point '(2,0)'(3,1),(2,0)
path + pathpath 连接两个打开的路径(如果其中一个路径是关闭的,则返回NULL)。path '[(0,0),(1,1)]' + path '[(2,2),(3,3),(4,4)]'[(0,0),(1,1),(2,2),(3,3),(4,4)]
geometric_type - point*geometric_type* 从第一个参数的每个点的坐标中减去第二个 point 的坐标,从而执行翻译。 适用于 pointboxpathcirclebox '(1,1),(0,0)' - point '(2,0)'(-1,1),(-2,0)
geometric_type * point*geometric_type* 将第一个参数的每个点乘上第二个 point(将点视为由实部和虚部表示的复数,并执行标准的复数乘法)。 如果将第二个 point 解释为向量,这等价于将对象的大小和到原点的距离按向量的长度缩放,并以向量与 x 轴的夹角绕原点逆时针旋转。 适用于 point, box,[a] path, circle.。path '((0,0),(1,0),(1,1))' * point '(3.0,0)'((0,0),(3,0),(3,3))``path '((0,0),(1,0),(1,1))' * point(cosd(45), sind(45))((0,0),(0.7071067811865475,0.7071067811865475),(0,1.414213562373095))
geometric_type / point*geometric_type* 将第一个参数的每个点除以第二个 point(将点视为由实部和虚部表示的复数,并执行标准的复数除法)。 如果将第二个 point 解释为向量,这等价于将物体的大小和到原点的距离按向量的长度向下缩放,并以向量与 x 轴的夹角围绕原点顺时针旋转。 适用于 point, box,[a] path,circlepath '((0,0),(1,0),(1,1))' / point '(2.0,0)'((0,0),(0.5,0),(0.5,0.5))``path '((0,0),(1,0),(1,1))' / point(cosd(45), sind(45))((0,0),(0.7071067811865476,-0.7071067811865476),(1.4142135623730951,0))
@-@ geometric_typedouble precision 计算总长度。适用于 lseg, path.@-@ path '[(0,0),(1,0),(1,1)]'2
@@ geometric_typepoint 计算中心点。适用于 box, lseg, path, polygon, circle.@@ box '(2,2),(0,0)'(1,1)
# geometric_typeinteger 返回点的数量。适用于 path, polygon# path '((1,0),(0,1),(-1,0))'3
geometric_type # geometric_typepoint 计算交点,如果没有则为 NULL。适用于 lseg, linelseg '[(0,0),(1,1)]' # lseg '[(1,0),(0,1)]'(0.5,0.5)
box # boxbox 计算两个方框的交集,如果没有则为 NULL。box '(2,2),(-1,-1)' # box '(1,1),(-2,-2)'(1,1),(-1,-1)
geometric_type ## geometric_typepoint 计算第二个对象上离第一个对象最近的点。适用于这些类型对: (point, box), (point, lseg), (point, line), (lseg, box), (lseg, lseg), (lseg, line), (line, box), (line, lseg).point '(0,0)' ## lseg '[(2,0),(0,2)]'(1,1)
geometric_type <-> geometric_typedouble precision 计算对象之间的距离。适用于所有七种几何类型,适用于 point 与另一种几何类型的所有组合,以及这些额外的类型对:(box, lseg), (box, line), (lseg, line), (polygon, circle) (以及易子情况下)。circle '<(0,0),1>' <-> circle '<(5,0),1>'3
geometric_type @> geometric_typeboolean 第一个对象包含第二个对象吗?适用于这些类型对: (box, point), (box, box), (path, point), (polygon, point), (polygon, polygon), (circle, point), (circle, circle).circle '<(0,0),2>' @> point '(1,1)'t
geometric_type <@ geometric_typeboolean 第一个对象包含在第二个对象之中还是在第二个对象之上?适用于这些类型对: (point, box), (point, lseg), (point, line), (point, path), (point, polygon), (point, circle), (box, box), (lseg, box), (lseg, line), (polygon, polygon), (circle, circle).point '(1,1)' <@ circle '<(0,0),2>'t
geometric_type && geometric_typeboolean 这些对象有重叠吗?(一个共同点使之为真。) 适用于 boxpolygoncirclebox '(1,1),(0,0)' && box '(2,2),(0,0)'t
geometric_type << geometric_typeboolean 第一个对象完全位于第二个对象的左边吗?适用于 point, box, polygon, circlecircle '<(0,0),1>' << circle '<(5,0),1>'t
geometric_type >> geometric_typeboolean 第一个对象完全位于第二个对象的右边吗?适用于 point, box, polygon, circlecircle '<(5,0),1>' >> circle '<(0,0),1>'t
geometric_type &< geometric_typeboolean 第一个对象没有延伸到第二个对象的右侧吗? 适用于 box, polygon, circlebox '(1,1),(0,0)' &< box '(2,2),(0,0)'t
geometric_type &> geometric_typeboolean 第一个对象没有延伸到第二个对象的左侧吗? 适用于 box, polygon, circlebox '(3,3),(0,0)' &> box '(2,2),(0,0)'t
geometric_type <<| geometric_typeboolean 第一个对象是否确定位于第二个对象下面? 适用于 box, polygon, circlebox '(3,3),(0,0)' <<| box '(5,5),(3,4)'t
geometric_type |>> geometric_typeboolean 第一个对象是否确定位于第二个对象上面? 适用于 box, polygon, circle.box '(5,5),(3,4)' |>> box '(3,3),(0,0)'t
geometric_type &<| geometric_typeboolean 第一个对象是否没有扩展到第二个对象上面? 适用于 box, polygon, circle.box '(1,1),(0,0)' &<| box '(2,2),(0,0)'t
geometric_type |&> geometric_typeboolean 第一个对象是否没有扩展到第二个对象下面? 适用于 box, polygon, circle.box '(3,3),(0,0)' |&> box '(2,2),(0,0)'t
box <^ boxboolean 第一个对象是否位于第二个对象下面(允许边缘相切)?box '((1,1),(0,0))' <^ box '((2,2),(1,1))'t
point <^ pointboolean 第一个对象是否确定位于第二个对象下面? (这个操作符命名错误; 它应该是 <<|.)point '(1,0)' <^ point '(1,1)'t
box >^ boxboolean 第一个对象是否位于第二个对象上面(允许边缘相切)?box '((2,2),(1,1))' >^ box '((1,1),(0,0))'t
point >^ pointboolean 第一个对象是否确定位于第二个对象上面? (这个操作符命名错误, 它应该是 |>>。)point '(1,1)' >^ point '(1,0)'t
geometric_type ?# geometric_typeboolean 这些对象是否相交? 适用于这些类型对: (box, box), (lseg, box), (lseg, lseg), (lseg, line), (line, box), (line, line), (path, path).lseg '[(-1,0),(1,0)]' ?# box '(2,2),(-2,-2)'t
?- lineboolean``?- lsegboolean 线是水平的??- lseg '[(-1,0),(1,0)]'t
point ?- pointboolean 点是否水平对齐(即具有相同的 y 坐标)?point '(1,0)' ?- point '(0,0)'t
?| lineboolean``?| lsegboolean 线是纵向的??| lseg '[(-1,0),(1,0)]'f
point ?| pointboolean 点是否垂直对齐(即具有相同的 x 坐标)?point '(0,1)' ?| point '(0,0)'t
line ?-| lineboolean``lseg ?-| lsegboolean 线是垂直的?lseg '[(0,0),(0,1)]' ?-| lseg '[(0,0),(1,0)]'t
line ?|| lineboolean``lseg ?|| lsegboolean 线是平行的?lseg '[(-1,0),(1,0)]' ?|| lseg '[(-1,2),(1,2)]'t
geometric_type ~= geometric_typeboolean 这些对象是相同的吗?适用于 point, box, polygon, circle.polygon '((0,0),(1,1))' ~= polygon '((1,1),(0,0))'t
“Rotating” 用这些操作符“旋转”一个盒子,只会移动它的角点:这个盒子仍然被认为有平行于轴的边。 因此,盒子的大小并没有像真正的旋转那样得到保留。

小心

请注意“same as”操作符(~=),表示 pointboxpolygoncircle 类型的一般相等概念。 这些类型中的某些还有一个=操作符,但是=只比较相同的面积。 其它的标量比较操作符 (<=等等),在这些类型可用的地方,同样比较区域。

注意

在 AntDB 之前,包含操作符@><@被分别称为~@。 这些名字仍然可以使用,但是已被废除并且最终将被移除。

几何函数

函数描述例子
area ( geometric_type ) → double precision 计算面积。适用于 box, path, circlepath 输入必须封闭,否则返回 NULL。同样,如果 path 是自交叉的,结果可能是没有意义的。area(box '(2,2),(0,0)')4
center ( geometric_type ) → point 计算中心点。适用于 box, circlecenter(box '(1,2),(0,0)')(0.5,1)
diagonal ( box ) → lseg 提取框的对角线作为线段(与 lseg(box) 相同)。diagonal(box '(1,2),(0,0)')[(1,2),(0,0)]
diameter ( circle ) → double precision 计算圆的直径。diameter(circle '<(0,0),2>')4
height ( box ) → double precision 计算框的垂直尺寸。height(box '(1,2),(0,0)')2
isclosed ( path ) → boolean 路径是否封闭?isclosed(path '((0,0),(1,1),(2,0))')t
isopen ( path ) → boolean 路径是否开放?isopen(path '[(0,0),(1,1),(2,0)]')t
length ( geometric_type ) → double precision 计算总长度。适用于 lseg, pathlength(path '((-1,0),(1,0))')4
npoints ( geometric_type ) → integer 返回点的数量。适用于 path, polygonnpoints(path '[(0,0),(1,1),(2,0)]')3
pclose ( path ) → path 将路径转换为封闭形式。pclose(path '[(0,0),(1,1),(2,0)]')((0,0),(1,1),(2,0))
popen ( path ) → path 将路径转换为开放形式。popen(path '((0,0),(1,1),(2,0))')[(0,0),(1,1),(2,0)]
radius ( circle ) → double precision 计算圆的半径。radius(circle '<(0,0),2>')2
slope ( point, point ) → double precision 计算通过两点所画直线的斜率。slope(point '(0,0)', point '(2,1)')0.5
width ( box ) → double precision 计算框的水平大小。width(box '(1,2),(0,0)')1

几何类型转换函数

函数描述例子
box ( circle ) → box 计算框中内刻的圆形。box(circle '<(0,0),2>')(1.414213562373095,1.414213562373095),(-1.414213562373095,-1.414213562373095)
box ( point ) → box 将点转换为空框。box(point '(1,0)')(1,0),(1,0)
box ( point, point ) → box 将任意两个角点转换为框。box(point '(0,1)', point '(1,0)')(1,1),(0,0)
box ( polygon ) → box 计算多边形的边界框。box(polygon '((0,0),(1,1),(2,0))')(2,1),(0,0)
bound_box ( box, box ) → box 计算两个方框的边界框。bound_box(box '(1,1),(0,0)', box '(4,4),(3,3)')(4,4),(0,0)
circle ( box ) → circle 计算最小的圆形包围框。circle(box '(1,1),(0,0)')<(0.5,0.5),0.7071067811865476>
circle ( point, double precision ) → circle 从圆心和半径构造圆。circle(point '(0,0)', 2.0)<(0,0),2>
circle ( polygon ) → circle 将多边形转换为圆。圆心是多边形各点位置的平均值,半径是多边形各点到圆心的平均距离。circle(polygon '((0,0),(1,3),(2,0))')<(1,1),1.6094757082487299>
line ( point, point ) → line 将两个点转换成通过它们的直线。line(point '(-1,0)', point '(1,0)'){0,-1,0}
lseg ( box ) → lseg 提取框的对角线作为线段。lseg(box '(1,0),(-1,0)')[(1,0),(-1,0)]
lseg ( point, point ) → lseg 从两个端点构造线段。lseg(point '(-1,0)', point '(1,0)')[(-1,0),(1,0)]
path ( polygon ) → path 将多边形转换为具有点的相同列表的封闭路径。path(polygon '((0,0),(1,1),(2,0))')((0,0),(1,1),(2,0))
point ( double precision, double precision ) → point 从它的坐标构造点。point(23.4, -44.5)(23.4,-44.5)
point ( box ) → point 计算框的中心。point(box '(1,0),(-1,0)')(0,0)
point ( circle ) → point 计算圆心。point(circle '<(0,0),2>')(0,0)
point ( lseg ) → point 计算线段的中心。point(lseg '[(-1,0),(1,0)]')(0,0)
point ( polygon ) → point 计算多边形的中心(多边形的点位置的平均值)。point(polygon '((0,0),(1,1),(2,0))')(1,0.3333333333333333)
polygon ( box ) → polygon 将框转换为 4 点多边形。polygon(box '(1,1),(0,0)')((0,0),(0,1),(1,1),(1,0))
polygon ( circle ) → polygon 将圆转换为 12 点多边形。polygon(circle '<(0,0),2>')((-2,0),(-1.7320508075688774,0.9999999999999999),(-1.0000000000000002,1.7320508075688772),(-1.2246063538223773e-16,2),(0.9999999999999996,1.7320508075688774),(1.732050807568877,1.0000000000000007),(2,2.4492127076447545e-16),(1.7320508075688776,-0.9999999999999994),(1.0000000000000009,-1.7320508075688767),(3.673819061467132e-16,-2),(-0.9999999999999987,-1.732050807568878),(-1.7320508075688767,-1.0000000000000009))
polygon ( integer, circle ) → polygon 将圆转换为 n 点多边形。polygon(4, circle '<(3,0),1>')((2,0),(3,1),(4,1.2246063538223773e-16),(3,-1))
polygon ( path ) → polygon 将封闭路径转换为具有点的相同列表的多边形。polygon(path '((0,0),(1,1),(2,0))')((0,0),(1,1),(2,0))

可以把一个 point 的两个组成数字当作具有索引 0 和 1 的数组访问。例如,如果 t.p 是一个 point 列,那么 SELECT p[0] FROM t 检索 X 座标而 UPDATE t SET p[1] = ...改变 Y 座标。同样,box 或者 lseg 类型的值可以当作两个 point 值的数组值看待。

网络地址函数和操作符

IP 网络地址类型,cidrinet。任何 cidr 值都可以隐式地转换到 inet;因此,下面在 inet 上操作的操作符和函数也可以在 cidr 值上工作。(对于 inetcidr 有单独的函数,这是因为这两种情况的行为应该是不同的。) 此外,它允许将 inet 值转换为 cidr。 当这样做的时候,子网掩码右边的任何位都被静默地置零,以创建一个有效的 cidr 值。

IP 地址操作符

操作符描述例子
inet << inetboolean 子网是否严格包含在子网中?这个操作符和后续的四个操作符测试子网包含情况。 它们只考虑两个地址的网络部分(忽略网络掩码右侧的任何位),并确定一个网络与另一个网络相同或者是相同的子网。inet '192.168.1.5' << inet '192.168.1/24't``inet '192.168.0.5' << inet '192.168.1/24'f``inet '192.168.1/24' << inet '192.168.1/24'f
inet <<= inetboolean 子网是否包含或等于子网?inet '192.168.1/24' <<= inet '192.168.1/24't
inet >> inetboolean 子网是否严格包含子网?inet '192.168.1/24' >> inet '192.168.1.5't
inet >>= inetboolean 子网是否包含或等于子网?inet '192.168.1/24' >>= inet '192.168.1/24't
inet && inetboolean 其中一个子网包含或等于另一个子网?inet '192.168.1/24' && inet '192.168.1.80/28't``inet '192.168.1/24' && inet '192.168.2.0/28'f
~ inetinet 计算位 NOT。~ inet '192.168.1.6'63.87.254.249
inet & inetinet 计算位 AND。inet '192.168.1.6' & inet '0.0.0.255'0.0.0.6
inet | inetinet 计算位 OR。inet '192.168.1.6' | inet '0.0.0.255'192.168.1.255
inet + bigintinet 向地址添加偏移量。inet '192.168.1.6' + 25192.168.1.31
bigint + inetinet 向地址添加偏移量。200 + inet '::ffff:fff0:1'::ffff:255.240.0.201
inet - bigintinet 从地址中减去偏移量。inet '192.168.1.43' - 36192.168.1.7
inet - inetbigint 计算两个地址的差值。inet '192.168.1.43' - inet '192.168.1.19'24``inet '::1' - inet '::ffff:1'-4294901760

IP地址的函数

函数描述例子
abbrev ( inet ) → text 创建缩略的文本显示格式。 (结果与 inet 输出函数产生的结果相同;它只是在与显式转换为 text 的结果比较时才被“abbreviated”, 由于历史原因,它永远不会抑制子网掩码部分。)abbrev(inet '10.1.0.0/32')10.1.0.0
abbrev ( cidr ) → text 创建缩写的文本显示格式。(缩写包括在子网掩码的右侧删除所有零字节)abbrev(cidr '10.1.0.0/16')10.1/16
broadcast ( inet ) → inet 为地址的网络计算广播地址。broadcast(inet '192.168.1.5/24')192.168.1.255/24
family ( inet ) → integer 返回地址的系列:4对应 IPv4,6对应 IPv6。family(inet '::1')6`
host ( inet ) → text 返回 IP 地址文本,忽略子网掩码。host(inet '192.168.1.0/24')192.168.1.0
hostmask ( inet ) → inet 为地址的网络计算主机掩码。hostmask(inet '192.168.23.20/30')0.0.0.3
inet_merge ( inet, inet ) → cidr 计算包含两个给定网络的最小网络。inet_merge(inet '192.168.1.5/24', inet '192.168.2.5/24')192.168.0.0/22
inet_same_family ( inet, inet ) → boolean 测试地址是否属于同一 IP 族。inet_same_family(inet '192.168.1.5/24', inet '::1')f
masklen ( inet ) → integer 以比特位返回子网掩码长度。masklen(inet '192.168.1.5/24')24
netmask ( inet ) → inet 为地址的网络计算网络掩码。netmask(inet '192.168.1.5/24')255.255.255.0
network ( inet ) → cidr 返回地址的网络部分,将子网掩码右边的部分归零。(这相当于将值转换为 cidr。)network(inet '192.168.1.5/24')192.168.1.0/24
set_masklen ( inet, integer ) → inet 设置 inet 值的子网掩码长度。地址部分不改变。set_masklen(inet '192.168.1.5/24', 16)192.168.1.5/16
set_masklen ( cidr, integer ) → cidr 设置 cidr 值的子网掩码长度。新子网掩码右侧的地址位设置为零。set_masklen(cidr '192.168.1.0/24', 16)192.168.0.0/16
text ( inet ) → text 以文本形式返回未缩写的 IP 地址和子网掩码长度。(这与显式转换为 text 的结果相同。)text(inet '192.168.1.5')192.168.1.5/32

提示

abbrevhosttext 函数主要用于为 IP 地址提供另一种显示格式。

MAC 地址类型, macaddrmacaddr8,支持常用比较操作符以及下表中所示的特殊函数。 此外,它们支持位元逻辑操作符~, &| (NOT, AND 和 OR),就像上面对 IP 地址所示的那样。

MAC 地址函数

函数描述例子
trunc ( macaddr ) → macaddr 将地址的最后 3 个字节设置为零。其余的前缀可以与特定的制造商关联(使用 AntDB 中没有包含的数据)。trunc(macaddr '12:34:56:78:90:ab')12:34:56:00:00:00
trunc ( macaddr8 ) → macaddr8 将地址的最后 5 个字节设置为零。其余的前缀可以与特定的制造商关联(使用 AntDB 中没有包含的数据)。trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')12:34:56:00:00:00:00:00
macaddr8_set7bit ( macaddr8 ) → macaddr8 将地址的第 7 位设置为 1,创建所谓的 modified EUI-64,用于包含在 IPv6 地址中。macaddr8_set7bit(macaddr8 '00:34:56:ab:cd:ef')02:34:56:ff:fe:ab:cd:ef

文本搜索函数和操作符

下表总结了为全文搜索提供的函数和操作符。

文本搜索操作符

操作符描述例子
tsvector @@ tsqueryboolean``tsquery @@ tsvectorboolean``tsvector 匹配tsquery吗?(参数可以按任意顺序给出。)to_tsvector('fat cats ate rats') @@ to_tsquery('cat & rat')t
text @@ tsqueryboolean 隐式调用to_tsvector() 后的文本字符串匹配 tsquery 么 ?'fat cats ate rats' @@ to_tsquery('cat & rat')t
tsvector @@@ tsqueryboolean``tsquery @@@ tsvectorboolean 这是@@已弃用的同义词。to_tsvector('fat cats ate rats') @@@ to_tsquery('cat & rat')t
tsvector || tsvectortsvector 连接两个 tsvector。如果两个输入都包含词素位置,则相应地调整第二个输入的位置。'a:1 b:2'::tsvector || 'c:1 d:2 b:3'::tsvector'a':1 'b':2,5 'c':3 'd':4
tsquery && tsquerytsquery ANDs 两个 tsquery 一起,生成一个匹配两个输入查询的匹配文档的查询。'fat | rat'::tsquery && 'cat'::tsquery( 'fat' | 'rat' ) & 'cat'
tsquery || tsquerytsquery ORs 两个 tsquery 一起,生成一个匹配两个输入查询的匹配文档的查询。'fat | rat'::tsquery || 'cat'::tsquery'fat' | 'rat' | 'cat'
!! tsquerytsquery 否定 tsquery,生成一个与输入查询不匹配的匹配文档的查询。!! 'cat'::tsquery!'cat'
tsquery <-> tsquerytsquery 构造一个短语查询,如果两个输入查询在连续的词素上匹配,该查询将进行匹配。to_tsquery('fat') <-> to_tsquery('rat')'fat' <-> 'rat'
tsquery @> tsqueryboolean 第一个 tsquery 包含了第二个吗?(这只考虑出现在一个查询中的所有词素是否出现在另一个查询中,忽略了组合操作符。)'cat'::tsquery @> 'cat & rat'::tsqueryf
tsquery <@ tsqueryboolean 第一个 tsquery 包含在第二个中吗?(这只考虑出现在一个查询中的所有词素是否出现在另一个查询中,而忽略了组合操作符。)'cat'::tsquery <@ 'cat & rat'::tsqueryt``'cat'::tsquery <@ '!cat & rat'::tsqueryt

文本搜索函数

函数描述例子
array_to_tsvector ( text[] ) → tsvector 将词素数组转换为 tsvector。给定的字符串按原样使用,不做进一步处理。array_to_tsvector('{fat,cat,rat}'::text[])'cat' 'fat' 'rat'
get_current_ts_config ( ) → regconfig 返回当前默认文本搜索配置的 OID(由 default_text_search_config 所设定的)。get_current_ts_config()english
length ( tsvector ) → integer 返回 tsvector 中的词位数。length('fat:2,4 cat:3 rat:5A'::tsvector)3
numnode ( tsquery ) → integer 返回 tsquery 中词位和操作符的数目。numnode('(fat & rat) | cat'::tsquery)5
plainto_tsquery ( [ config regconfig, ] query text ) → tsquery 将文本转换为 tsquery,根据指定的或默认配置对单词进行标准化。 字符串中的任何标点符号都会被忽略(它不决定查询操作符)。结果查询匹配文本中包含所有非停止词的文档。plainto_tsquery('english', 'The Fat Rats')'fat' & 'rat'
phraseto_tsquery ( [ config regconfig, ] query text ) → tsquery 将文本转换为 tsquery,根据指定的或默认配置对单词进行标准化。 字符串中的任何标点符号都会被忽略(它不决定查询操作符)。结果查询匹配包含文本中所有非停止词的短语。phraseto_tsquery('english', 'The Fat Rats')'fat' <-> 'rat'``phraseto_tsquery('english', 'The Cat and Rats')'cat' <2> 'rat'
websearch_to_tsquery ( [ config regconfig, ] query text ) → tsquery 将文本转换为 tsquery,根据指定的或默认配置对单词进行标准化。引用的单词序列被转换为短语测试。 “or”一词被理解为产生 OR 操作符,而破折号产生 NOT 操作符;其他标点符号被忽略。这类似于一些常见的网络搜索工具的行为。websearch_to_tsquery('english', '"fat rat" or cat dog')'fat' <-> 'rat' | 'cat' & 'dog'
querytree ( tsquery ) → text 生成 tsquery 的可转位部分的表示。结果为空或仅为 T 表示不可索引查询。querytree('foo & ! bar'::tsquery)'foo'
setweight ( vector tsvector, weight "char" ) → tsvector 将指定的 weight 赋给 vector 的每个元素。setweight('fat:2,4 cat:3 rat:5B'::tsvector, 'A')'cat':3A 'fat':2A,4A 'rat':5A
setweight ( vector tsvector, weight "char", lexemes text[] ) → tsvector 将指定的 weight 赋给列在 lexemes 中的 vector 元素。setweight('fat:2,4 cat:3 rat:5,6B'::tsvector, 'A', '{cat,rat}')'cat':3A 'fat':2,4 'rat':5A,6A
strip ( tsvector ) → tsvectortsvector 中移除位置和权重。strip('fat:2,4 cat:3 rat:5A'::tsvector)'cat' 'fat' 'rat'
to_tsquery ( [ config regconfig, ] query text ) → tsquery 将文本转换为 tsquery,根据指定的或默认配置对单词进行标准化。单词必须由有效的 tsquery 操作符组合。to_tsquery('english', 'The & Fat & Rats')'fat' & 'rat'
to_tsvector ( [ config regconfig, ] document text ) → tsvector 将文本转换为 tsvector,根据指定的或默认配置对单词进行标准化。结果中包含位置信息。to_tsvector('english', 'The Fat Rats')'fat':2 'rat':3
to_tsvector ( [ config regconfig, ] document json ) → tsvector``to_tsvector ( [ config regconfig, ] document jsonb ) → tsvector 将 JSON 文档中的每个字符串值转换为 tsvector,根据指定的或默认配置对单词进行标准化。 然后将结果按文档顺序连接起来以产生输出。位置信息就像在每对字符串值之间存在一个停止词一样生成。 (注意,当输入为 jsonb 时,JSON 对象的字段的“document order”取决于实现;请观察这些例子中的差异。)to_tsvector('english', '{"aa": "The Fat Rats", "b": "dog"}'::json)'dog':5 'fat':2 'rat':3``to_tsvector('english', '{"aa": "The Fat Rats", "b": "dog"}'::jsonb)'dog':1 'fat':4 'rat':5
json_to_tsvector ( [ config regconfig, ] document json, filter jsonb ) → tsvector``jsonb_to_tsvector ( [ config regconfig, ] document jsonb, filter jsonb ) → tsvector 选择 filter 请求的 JSON 文档中的每个项,并将每个项转换为 tsvector,根据指定的或默认配置对单词进行标准化。 然后将结果按文档顺序连接起来以产生输出。位置信息就像在每对选定的项目之间存在一个停止词一样生成。 (注意,当输入为 jsonb 时,JSON 对象字段的“document order”取决于实现。)filter 必须是一个 jsonb 数组,其中包含 0 个或多个关键字: "string"(包括所有字符串值), "numeric"(包括所有数值), "boolean"(包括所有布尔值), "key"(包括所有键)或 "all"(包括以上所有关键字)。 作为一种特殊情况,该 filter 也可以是这些关键字之一的简单 JSON 值。json_to_tsvector('english', '{"a": "The Fat Rats", "b": 123}'::json, '["string", "numeric"]')'123':5 'fat':2 'rat':3``json_to_tsvector('english', '{"cat": "The Fat Rats", "dog": 123}'::json, '"all"')'123':9 'cat':1 'dog':7 'fat':4 'rat':5
ts_delete ( vector tsvector, lexeme text ) → tsvectorvector 中删除任何出现的给定 lexemets_delete('fat:2,4 cat:3 rat:5A'::tsvector, 'fat')'cat':3 'rat':5A
ts_delete ( vector tsvector, lexemes text[] ) → tsvectorvector 中删除 lexemes 中出现的任何词位。ts_delete('fat:2,4 cat:3 rat:5A'::tsvector, ARRAY['fat','rat'])'cat':3
ts_filter ( vector tsvector, weights "char"[] ) → tsvector 只从 vector 中选择具有给定 weights 的元素。ts_filter('fat:2,4 cat:3b,7c rat:5A'::tsvector, '{a,b}')'cat':3B 'rat':5A
ts_headline ( [ config regconfig, ] document text, query tsquery [, options text ] ) → text 以缩写形式显示 documentquery 的匹配项,该匹配项必须是原始文本,而不是 tsvector。 在匹配查询之前,文档中的单词将根据指定的或默认的配置进行规范化。 ts_headline('The fat cat ate the rat.', 'cat')The fat <b>cat</b> ate the rat.
ts_headline ( [ config regconfig, ] document json, query tsquery [, options text ] ) → text``ts_headline ( [ config regconfig, ] document jsonb, query tsquery [, options text ] ) → text 以缩写形式显示匹配 JSON*document*中字符串值中的 queryts_headline('{"cat":"raining cats and dogs"}'::jsonb, 'cat'){"cat": "raining <b>cats</b> and dogs"}
ts_rank ( [ weights real[], ] vector tsvector, query tsquery [, normalization integer ] ) → real 计算一个分数,显示 vectorquery 的匹配程度。ts_rank(to_tsvector('raining cats and dogs'), 'cat')0.06079271
ts_rank_cd ( [ weights real[], ] vector tsvector, query tsquery [, normalization integer ] ) → real 使用覆盖密度算法计算一个分数,显示 vectorquery 的匹配程度。ts_rank_cd(to_tsvector('raining cats and dogs'), 'cat')0.1
ts_rewrite ( query tsquery, target tsquery, substitute tsquery ) → tsqueryquery 中使用 substitute 替换出现的 targetts_rewrite('a & b'::tsquery, 'a'::tsquery, 'foo|bar'::tsquery)'b' & ( 'foo' | 'bar' )
ts_rewrite ( query tsquery, select text ) → tsquery 根据目标替换部分 query,并替换通过执行 SELECT 命令获得的查询。 SELECT ts_rewrite('a & b'::tsquery, 'SELECT t,s FROM aliases')'b' & ( 'foo' | 'bar' )
tsquery_phrase ( query1 tsquery, query2 tsquery ) → tsquery 构造一个短语查询,在连续的词位上搜索 query1query2 的匹配项(与<->操作符相同)。tsquery_phrase(to_tsquery('fat'), to_tsquery('cat'))'fat' <-> 'cat'
tsquery_phrase ( query1 tsquery, query2 tsquery, distance integer ) → tsquery 构造一个短语查询,用于搜索 query1query2 的匹配项,这些匹配项恰好出现在 distance 词位之间。tsquery_phrase(to_tsquery('fat'), to_tsquery('cat'), 10)'fat' <10> 'cat'
tsvector_to_array ( tsvector ) → text[]tsvector 转换为词位的数组。tsvector_to_array('fat:2,4 cat:3 rat:5A'::tsvector){cat,fat,rat}
unnest ( tsvector ) → setof record ( lexeme text, positions smallint[], weights text ) 将 tsvector 展开为一组行,每个行对应一个词位。SELECT * FROM unnest('cat:3 fat:2,4 rat:5A'::tsvector) →``` lexemepositionsweights --------+-----------+--------- cat{3}{D} fat{2,4}{D,D} rat{5}{A} `

注意

所有接受一个可选的 regconfig 参数的文本搜索函数在该参数被忽略时,使用由 default_text_search_config 指定的配置。

单独列出下表中的函数,因为它们通常不被用于日常的文本搜索操作。 它们主要有助于开发和调试新的文本搜索配置。

文本搜索调试函数

函数描述例子
ts_debug ( [ config regconfig, ] document text ) → setof record ( alias text, description text, token text, dictionaries regdictionary[], dictionary regdictionary, lexemes text[] ) 根据指定的或默认的文本搜索配置从 document 中提取和标准化标记,并返回关于每个标记是如何处理的信息。ts_debug('english', 'The Brightest supernovaes')(asciiword,"Word, all ASCII",The,{english_stem},english_stem,{}) ...
ts_lexize ( dict regdictionary, token text ) → text[] 如果字典知道输入标记,则返回替换词位数组;如果字典知道标记,但它是停止词,则返回空数组;如果它不是已知词,则返回 NULL。ts_lexize('english_stem', 'stars'){star}
ts_parse ( parser_name text, document text ) → setof record ( tokid integer, token text ) 使用命名的解析器从 document 中提取标记。ts_parse('default', 'foo - bar')(1,foo) ...
ts_parse ( parser_oid oid, document text ) → setof record ( tokid integer, token text ) 使用 OID 指定的解析器从 *document*中提取标记。 ts_parse(3722, 'foo - bar')(1,foo) ...
ts_token_type ( parser_name text ) → setof record ( tokid integer, alias text, description text ) 返回一个表,该表描述命名解析器可以识别的每种类型的标记。ts_token_type('default')(1,asciiword,"Word, all ASCII") ...
ts_token_type ( parser_oid oid ) → setof record ( tokid integer, alias text, description text ) 返回一个表,该表描述 OID 指定的解析器可以识别的每种标记类型。ts_token_type(3722)(1,asciiword,"Word, all ASCII") ...
ts_stat ( sqlquery text [, weights text ] ) → setof record ( word text, ndoc integer, nentry integer ) 执行 sqlquery,该查询必须返回单个 tsvector 列,并返回关于数据中包含的每个不同词位的统计信息。 ts_stat('SELECT vector FROM apod')(foo,10,15) ...

UUID 函数

AntDB 包含一个函数来生成 UUID:

gen_random_uuid () → uuid

此函数返回一个版本 4(随机)的 UUID。这是最常用的 UUID 类型,适用于大多数应用程序。

uuid-ossp 模块提供了额外的功能,用于实现生成 UUIDs 的其他标准算法。

XML 函数

本节中描述的函数以及类函数的表达式都在类型 xml 的值上操作。用于在值和类型 xml 之间转换的类函数的表达式 xmlparsexmlserialize 记录在这里,而不是在本节中。

使用大部分这些函数要求 AntDB 使用了 configure --with-libxml 进行编译。

产生 XML 内容

有一组函数和类函数的表达式可以用来从 SQL 数据产生 XML 内容。它们特别适合于将查询结果格式化成 XML 文档以便于在客户端应用中处理。

xmlcomment

xmlcomment ( text ) → xml

函数 xmlcomment 创建了一个 XML 值,它包含一个使用指定文本作为内容的 XML 注释。 该文本不包含“--”或者也不会以一个“-”结尾,否则该结果的结构不是一个合法的 XML 注释。如果参数为空,结果也为空。

例子:

SELECT xmlcomment('hello');

  xmlcomment
--------------
 <!--hello-->

xmlconcat

xmlconcat ( xml [, ...] ) → xml

函数 xmlconcat 将由单个 XML 值组成的列表串接成一个单独的值,这个值包含一个 XML 内容片断。空值会被忽略,只有当没有参数为非空时结果才为空。

例子:

SELECT xmlconcat('<abc/>', '<bar>foo</bar>');

      xmlconcat
----------------------
 <abc/><bar>foo</bar>

如果 XML 声明存在,它们会按照下面的方式被组合。如果所有的参数值都有相同的 XML 版本声明,该版本将被用在结果中,否则将不使用版本。如果所有参数值有独立声明值“yes”,那么该值将被用在结果中。如果所有参数值都有一个独立声明值并且至少有一个为“no”,则“no”被用在结果中。否则结果中将没有独立声明。如果结果被决定要要求一个独立声明但是没有版本声明,将会使用一个版本 1.0 的版本声明,因为 XML 要求一个 XML 声明要包含一个版本声明。编码声明会被忽略并且在所有情况中都会被移除。

例子:

SELECT xmlconcat('<?xml version="1.1"?><foo/>', '<?xml version="1.1" standalone="no"?><bar/>');

             xmlconcat
-----------------------------------
 <?xml version="1.1"?><foo/><bar/>

xmlelement

xmlelement ( NAME name [, XMLATTRIBUTES ( attvalue [ AS attname ] [, ...] ) ] [, content [, ...]] ) → xml

表达式 xmlelement 使用给定名称、属性和内容产生一个 XML 元素。 语法中显示的 nameattname 项是简单的标识符,而不是值。 attvaluecontent 项是表达式,它们可以生成任何 AntDB 数据类型。 XMLATTRIBUTES 的参数生成 XML 元素的属性;将 content 值连接起来形成其内容。

例子:

SELECT xmlelement(name foo);

 xmlelement
------------
 <foo/>

SELECT xmlelement(name foo, xmlattributes('xyz' as bar));

    xmlelement
------------------
 <foo bar="xyz"/>

SELECT xmlelement(name foo, xmlattributes(current_date as bar), 'cont', 'ent');

             xmlelement
-------------------------------------
 <foo bar="2007-01-26">content</foo>

不是合法 XML 名字的元素名和属性名将被逃逸,逃逸的方法是将违反的字符用序列_x*HHHH*_替换,其中*HHHH*是被替换字符的 Unicode 代码点的十六进制表示。例如:

SELECT xmlelement(name "foo$bar", xmlattributes('xyz' as "a&b"));

            xmlelement
----------------------------------
 <foo_x0024_bar a_x0026_b="xyz"/>

如果属性值是一个列引用,则不需要指定一个显式的属性名,在这种情况下列的名字将被默认用于属性的名字。在其他情况下,属性必须被给定一个显式名称。因此这个例子是合法的:

CREATE TABLE test (a xml, b xml);
SELECT xmlelement(name test, xmlattributes(a, b)) FROM test;

但是下面这些不合法:

SELECT xmlelement(name test, xmlattributes('constant'), a, b) FROM test;
SELECT xmlelement(name test, xmlattributes(func(a, b))) FROM test;

如果指定了元素内容,它们将被根据其数据类型格式化。如果内容本身也是类型 xml,就可以构建复杂的 XML 文档。例如:

SELECT xmlelement(name foo, xmlattributes('xyz' as bar),
                            xmlelement(name abc),
                            xmlcomment('test'),
                            xmlelement(name xyz));

                  xmlelement
----------------------------------------------
 <foo bar="xyz"><abc/><!--test--><xyz/></foo>

其他类型的内容将被格式化为合法的 XML 字符数据。这意味着字符 <, >和 & 将被转换为实体。二进制数据(数据类型 bytea)将被表示成 base64 或十六进制编码,具体取决于配置参数 xmlbinary 的设置。

xmlforest

xmlforest ( content [ AS name ] [, ...] ) → xml

表达式 xmlforest 使用给定名称和内容产生一个元素的 XML 森林(序列)。 对于 xmlelement,每个 name 都必须是一个简单的标识符,而 content 表达式可以有任何数据类型。

例子:

SELECT xmlforest('abc' AS foo, 123 AS bar);

          xmlforest
------------------------------
 <foo>abc</foo><bar>123</bar>


SELECT xmlforest(table_name, column_name)
FROM information_schema.columns
WHERE table_schema = 'pg_catalog';

                                xmlforest
-----------------------------------------------------------------------
 <table_name>pg_authid</table_name><column_name>rolname</column_name>
 <table_name>pg_authid</table_name><column_name>rolsuper</column_name>
 ...

如在第二个例子中所见,如果内容值是一个列引用,元素名称可以被忽略,这种情况下默认使用列名。否则,必须指定一个名字。

如上文 xmlelement 所示,非法 XML 名字的元素名会被逃逸。相似地,内容数据也会被逃逸来产生合法的 XML 内容,除非它已经是一个 xml 类型。

注意如果 XML 森林由多于一个元素组成,那么它不是合法的 XML 文档,因此在 xmlelement 中包装 xmlforest 表达式会有用处。

xmlpi

xmlpi ( NAME name [, content ] ) → xml

表达式 xmlpi 创建一个 XML 处理指令。 对于 xmlelementname 必须是一个简单的标识符,而 content 表达式可以有任何数据类型。如果存在,content 不能包含字符序列?>

例子:

SELECT xmlpi(name php, 'echo "hello world";');

            xmlpi
-----------------------------
 <?php echo "hello world";?>

xmlroot

xmlroot ( xml, VERSION {text|NO VALUE} [, STANDALONE {YES|NO|NO VALUE} ] ) → xml

表达式 xmlroot 修改一个 XML 值的根结点的属性。如果指定了一个版本,它会替换根节点的版本声明中的值;如果指定了一个独立设置,它会替换根节点的独立声明中的值。

SELECT xmlroot(xmlparse(document '<?xml version="1.1"?><content>abc</content>'),
               version '1.0', standalone yes);

                xmlroot
----------------------------------------
 <?xml version="1.0" standalone="yes"?>
 <content>abc</content>

xmlagg

xmlagg ( xml ) → xml

和这里描述的其他函数不同,函数 xmlagg 是一个聚集函数。它将聚集函数调用的输入值串接起来,非常像 xmlconcat 所做的事情,除了串接是跨行发生的而不是在单一行的多个表达式上发生。

例子:

CREATE TABLE test (y int, x xml);
INSERT INTO test VALUES (1, '<foo>abc</foo>');
INSERT INTO test VALUES (2, '<bar/>');
SELECT xmlagg(x) FROM test;
        xmlagg
----------------------
 <foo>abc</foo><bar/>

为了决定串接的顺序,可以为聚集调用增加一个 ORDER BY 子句。例如:

SELECT xmlagg(x ORDER BY y DESC) FROM test;
        xmlagg
----------------------
 <bar/><foo>abc</foo>

推荐在以前的版本中使用下列非标准方法,并且它们在特定情况下仍然有用:

SELECT xmlagg(x) FROM (SELECT * FROM test ORDER BY y DESC) AS tab;
        xmlagg
----------------------
 <bar/><foo>abc</foo>

XML 谓词

这一节描述的表达式检查 xml 值的属性。

IS DOCUMENT

xml IS DOCUMENT → boolean

如果参数 XML 值是一个正确的 XML 文档,则 IS DOCUMENT 返回真,如果不是则返回假(即它是一个内容片断),或者是参数为空时返回空。

IS NOT DOCUMENT

xml IS NOT DOCUMENT → boolean

如果参数中的 XML 值是一个正确的 XML 文档,那么表达式 IS NOT DOCUMENT 返回假,否则返回真(也就是说它是一个内容片段),如果参数为空则返回空。

XMLEXISTS

XMLEXISTS ( text PASSING [BY {REF|VALUE}] xml [BY {REF|VALUE}] ) → boolean

函数 xmlexists 评价一个 XPath 1.0 表达式(第一个参数),以传递的 XML 值作为其上下文项。 如果评价的结果产生一个空节点集,该函数返回 false,如果产生任何其他值,则返回 true。 如果任何参数为空,则函数返回 null。 作为上下文项传递的非空值必须是一个 XML 文档,而不是内容片段或任何非 XML 值。

例子:

SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY VALUE '<towns><town>Toronto</town><town>Ottawa</town></towns>');

 xmlexists
------------
 t
(1 row)

xml_is_well_formed

xml_is_well_formed ( text ) → boolean
xml_is_well_formed_document ( text ) → boolean
xml_is_well_formed_content ( text ) → boolean

这些函数检查一个 text 串是不是一个良构的 XML,返回一个布尔结果。xml_is_well_formed_document 检查一个良构的文档,而 xml_is_well_formed_content 检查良构的内容。如果 xmloption 配置参数被设置为 DOCUMENTxml_is_well_formed 会做第一个函数的工作;如果配置参数被设置为 CONTENTxml_is_well_formed 会做第二个函数的工作。这意味着 xml_is_well_formed 对于检查一个到类型 xml 的简单造型是否会成功非常有用,而其他两个函数对于检查 XMLPARSE 的对应变体是否会成功有用。

例子:

SET xmloption TO DOCUMENT;
SELECT xml_is_well_formed('<>');
 xml_is_well_formed 
--------------------
 f
(1 row)

SELECT xml_is_well_formed('<abc/>');
 xml_is_well_formed 
--------------------
 t
(1 row)

SET xmloption TO CONTENT;
SELECT xml_is_well_formed('abc');
 xml_is_well_formed 
--------------------
 t
(1 row)

SELECT xml_is_well_formed_document('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</pg:foo>');
 xml_is_well_formed_document 
-----------------------------
 t
(1 row)

SELECT xml_is_well_formed_document('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</my:foo>');
 xml_is_well_formed_document 
-----------------------------
 f
(1 row)

最后一个例子显示了这些检查也包括名字空间是否正确地匹配。

处理 XML

要处理数据类型 xml 的值, AntDB 提供了函数 xpathxpath_exists,它们计算 XPath 1.0 表达式以及 XMLTABLE 表函数。

xpath

xpath ( xpath text, xml xml [, nsarray text[] ] ) → xml[]

函数 xpath 根据 XML 值*xml*计算 XPath 1.0 表达式 xpath (以文本形式给出)。 它返回一个 XML 值的数组,该数组对应于该 XPath 表达式产生的结点集合。 如果该 XPath 表达式返回一个标量值而不是一个结点集合,将会返回一个单一元素的数组。

第二个参数必须是一个良构的 XML 文档。特殊地,它必须有一个单一根结点元素。

该函数可选的第三个参数是一个名字空间映射的数组。这个数组应该是一个二维 text 数组,其第二轴长度等于 2(即它应该是一个数组的数组,其中每一个都由刚好 2 个元素组成)。每个数组项的第一个元素是名字空间的名称(别名),第二个元素是名字空间的 URI。并不要求在这个数组中提供的别名和在 XML 文档本身中使用的那些名字空间相同(换句话说,在 XML 文档中和在 xpath 函数环境中,别名都是本地的)。

例子:

SELECT xpath('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
             ARRAY[ARRAY['my', 'http://example.com']]);

 xpath  
--------
 {test}
(1 row)

要处理默认(匿名)命名空间,做这样的事情:

SELECT xpath('//mydefns:b/text()', '<a xmlns="http://example.com"><b>test</b></a>',
             ARRAY[ARRAY['mydefns', 'http://example.com']]);

 xpath
--------
 {test}
(1 row)

xpath_exists

xpath_exists ( xpath text, xml xml [, nsarray text[] ] ) → boolean

函数 xpath_existsxpath 函数的一种特殊形式。这个函数不是返回满足 XPath 1.0 表达式的单一 XML 值,它返回一个布尔值表示查询是否被满足(具体来说,它是否产生了空节点集以外的任何值)。这个函数等价于标准的 XMLEXISTS 谓词,不过它还提供了对一个名字空间映射参数的支持。

例子:

SELECT xpath_exists('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
                     ARRAY[ARRAY['my', 'http://example.com']]);

 xpath_exists  
--------------
 t
(1 row)

xmltable

XMLTABLE (
    [ XMLNAMESPACES ( namespace_uri AS namespace_name [, ...] ), ]
    row_expression PASSING [BY {REF|VALUE}] document_expression [BY {REF|VALUE}]
    COLUMNS name { type [PATH column_expression] [DEFAULT default_expression] [NOT NULL | NULL]
                  | FOR ORDINALITY }
            [, ...]
) → setof record

xmltable 表达式基于给定的 XML 值产生一个表、一个抽取行的 XPath 过滤器以及一个列定义集合。 虽然它在语法上类似于函数,但它只能作为一个表出现在查询的 FROM 子句中。

可选的 XMLNAMESPACES 子句是一个逗号分隔的名字空间定义列表。 其中每个 namespace_uri 是一个 text 表达式,每个 namespace_name 是一个简单的标识符。 它指定文档中使用的 XML 名字空间极其别名。当前不支持默认的名字空间说明。

所需的 row_expression 参数是一个求值的 XPath 1.0 表达式(以 text 形式给出),通过传递 XML 值 document_expression 作为其上下文项,得到一组 XML 节点。 这些节点就是 xmltable 转换为输出行的内容。如果 document_expression 为空,或者 row_expression 产生空节点集或节点集以外的任何值,则不会产生行。

document_expression 提供了上下文。row_expression 的项。 它必须是一个格式良好的 XML 文档;不接受片段/森林。BY REFBY VALUE 子句 如上文所讨论的那样,被接受但被忽略了。

在 SQL 标准中,xmltable 函数评估 XML 查询语言中的表达式。 但 AntDB 只允许使用 XPath 1.0 的 表达式。

需要的 COLUMNS 子句指定将在输出表中生成的列。有关格式,请参阅上面的语法摘要。 每个列都需要一个名称,作为一个数据类型(除非指定了 FOR ORDINALITY,在这种情况下类型 integer 是隐式的)。路径、默认值以及为空性子句是可选的。

被标记为 FOR ORDINALITY 的列将按照从 row_expression 的结果节点集中检索到的节点的顺序,从 1 开始,填充行号。最多只能有一个列被标记为 FOR ORDINALITY

注意

XPath 1.0 并没有为节点集中的节点指定顺序,因此依赖特定结果顺序的代码将取决于实现。

列的 column_expression 是一个 XPath 1.0 表达式,它对每一行都要进行求值,并以 row_expression 结果中的当前节点作为其上下文项,以找到列的值。 如果没有给出 column_expression,那么列名被用作隐式路径。

如果一个列的 XPath 表达式返回一个非 XML 值(在 XPath 1.0 中仅限于 string、boolean 或 double),而该列的 AntDB 类型不是 xml,那么该列将被设置为将值的字符串表示法分配给 AntDB 类型。 (如果值是布尔值,如果输出列的类型类别是数字,那么它的字符串表示方式将被认为是 10,否则 truefalse。)

如果一个列的 XPath 表达式返回一个非空的 XML 节点集,并且该列的 AntDB 类型是 xml,那么如果该列是文档或内容形式的,那么该列将被精确地分配表达式结果。

分配给 xml 输出列的非 XML 结果会产生内容,一个带有结果字符串值的单个文本节点。分配给任何其他类型的列的XML结果不能有一个以上的节点,否则会产生错误。如果正好有一个节点,则该列将被设置为将该节点的字符串值(如 XPath 1.0 string 函数定义的那样)分配给 AntDB 类型。

一个 XML 元素的字符串值是字符串值的协整,按文档的顺序。该元素中包含的所有文本节点及其子节点。字符串 元素的值是一个没有下级文本节点的元素的值是一个 空字符串(不是 NULL)。任何 xsi:nil 属性都会被忽略。请注意,两个非文本之间的 text() 节点只用空格,而两个非文本 元素,并且保留了 text() 上的前导白格。节点不被扁平化。XPath 1.0 中的 string 函数可以参考 XPath 1.0 中的 定义其他 XML 节点类型和非 XML 值的字符串值的规则。

这里介绍的转换规则并不完全是 SQL 标准中的转换规则。

如果路径表达式为给定行返回一个空节点集(通常情况下,当它不匹配时),该列将被设置为 NULL,除非指定了 default_expression ;然后使用评价该表达式产生的值。

default_expression,而不是在调用 xmltable 时立即被评价,而是在每次需要列的默认值时,都会被评价。 如果表达式符合稳定或不可更改的条件,则可以跳过重复评价。 这意味着,可以在 default_expression 中使用像 nextval 这样的不稳定函数。

列可能会被标记为 NOT NULL。如果一个 NOT NULL 列的 column_expression 不匹配任何东西并且没有 DEFAULT 或者 default_expression 也计算为空,则会报告一个错误。

例子:

CREATE TABLE xmldata AS SELECT
xml $$
<ROWS>
  <ROW id="1">
    <COUNTRY_ID>AU</COUNTRY_ID>
    <COUNTRY_NAME>Australia</COUNTRY_NAME>
  </ROW>
  <ROW id="5">
    <COUNTRY_ID>JP</COUNTRY_ID>
    <COUNTRY_NAME>Japan</COUNTRY_NAME>
    <PREMIER_NAME>Shinzo Abe</PREMIER_NAME>
    <SIZE unit="sq_mi">145935</SIZE>
  </ROW>
  <ROW id="6">
    <COUNTRY_ID>SG</COUNTRY_ID>
    <COUNTRY_NAME>Singapore</COUNTRY_NAME>
    <SIZE unit="sq_km">697</SIZE>
  </ROW>
</ROWS>
$$ AS data;

SELECT xmltable.*
  FROM xmldata,
       XMLTABLE('//ROWS/ROW'
                PASSING data
                COLUMNS id int PATH '@id',
                        ordinality FOR ORDINALITY,
                        "COUNTRY_NAME" text,
                        country_id text PATH 'COUNTRY_ID',
                        size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
                        size_other text PATH
                             'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
                        premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified');

 id | ordinality | COUNTRY_NAME | country_id | size_sq_km |  size_other  | premier_name  
----+------------+--------------+------------+------------+--------------+---------------
  1 |          1 | Australia    | AU         |            |              | not specified
  5 |          2 | Japan        | JP         |            | 145935 sq_mi | Shinzo Abe
  6 |          3 | Singapore    | SG         |        697 |              | not specified

接下来的例子展示了多个 text() 节点的串接、列名用作 XPath 过滤器的用法以及对空格、XML 注释和处理指令的处理:

CREATE TABLE xmlelements AS SELECT
xml $$
  <root>
   <element>  Hello<!-- xyxxz -->2a2<?aaaaa?> <!--x-->  bbb<x>xxx</x>CC  </element>
  </root>
$$ AS data;

SELECT xmltable.*
  FROM xmlelements, XMLTABLE('/root' PASSING data COLUMNS element text);
         element         
-------------------------
   Hello2a2   bbbxxxCC  

下面的例子展示了如何使用 XMLNAMESPACES 子句指定用在 XML 文档以及 XPath 表达式中的名字空间列表:

WITH xmldata(data) AS (VALUES ('
<example xmlns="http://example.com/myns" xmlns:B="http://example.com/b">
 <item foo="1" B:bar="2"/>
 <item foo="3" B:bar="4"/>
 <item foo="4" B:bar="5"/>
</example>'::xml)
)
SELECT xmltable.*
  FROM XMLTABLE(XMLNAMESPACES('http://example.com/myns' AS x,
                              'http://example.com/b' AS "B"),
             '/x:example/x:item'
                PASSING (SELECT data FROM xmldata)
                COLUMNS foo int PATH '@foo',
                  bar int PATH '@B:bar');
 foo | bar
-----+-----
   1 |   2
   3 |   4
   4 |   5
(3 rows)

将表映射到 XML

下面的函数将会把关系表的内容映射成 XML 值。它们可以被看成是 XML 导出功能:

table_to_xml ( table regclass, nulls boolean,
               tableforest boolean, targetns text ) → xml
query_to_xml ( query text, nulls boolean,
               tableforest boolean, targetns text ) → xml
cursor_to_xml ( cursor refcursor, count integer, nulls boolean,
                tableforest boolean, targetns text ) → xml

table_to_xml 映射由参数 table 传递的命名表的内容。regclass 类型接受使用常见标记标识表的字符串,包括可选的模式限定和双引号。query_to_xml 执行由参数 query 传递的查询并且映射结果集。cursor_to_xmlcursor 指定的游标中取出指定数量的行。如果需要映射一个大型的表,推荐这种变体,因为每一个函数都是在内存中构建结果值的。

如果 tableforest 为假,则结果的 XML 文档看起来像这样:

<tablename>
  <row>
    <columnname1>data</columnname1>
    <columnname2>data</columnname2>
  </row>

  <row>
    ...
  </row>

  ...
</tablename>

如果 tableforest 为真,结果是一个看起来像这样的 XML 内容片断:

<tablename>
  <columnname1>data</columnname1>
  <columnname2>data</columnname2>
</tablename>

<tablename>
  ...
</tablename>

...

如果没有表名可用,在映射一个查询或一个游标时,在第一种格式中使用串 table,在第二种格式中使用 row

这几种格式的选择由用户决定。第一种格式是一个正确的 XML 文档,它在很多应用中都很重要。如果结果值要被重组为一个文档,第二种格式在 cursor_to_xml 函数中更有用。前文讨论的产生 XML 内容的函数(特别是 xmlelement)可以被用来把结果修改成符合用户的要求。

数据值会被以前文的函数 xmlelement 中描述的相同方法映射。

参数 nulls 决定空值是否会被包含在输出中。如果为真,列中的空值被表示为:

<columnname xsi:nil="true"/>

其中 xsi 是 XML 模式实例的 XML 名字空间前缀。一个合适的名字空间声明将被加入到结果值中。如果为假,包含空值的列将被从输出中忽略掉。

参数 targetns 指定想要的结果的 XML 名字空间。如果没有想要的特定名字空间,将会传递一个空串。

下面的函数返回 XML 模式文档,这些文档描述上述对应函数所执行的映射:

table_to_xmlschema ( table regclass, nulls boolean,
                     tableforest boolean, targetns text ) → xml
query_to_xmlschema ( query text, nulls boolean,
                     tableforest boolean, targetns text ) → xml
cursor_to_xmlschema ( cursor refcursor, nulls boolean,
                      tableforest boolean, targetns text ) → xml

最重要的是相同的参数被传递来获得匹配的 XML 数据映射和 XML 模式文档。

下面的函数产生 XML 数据映射和对应的 XML 模式,并把产生的结果链接在一起放在一个文档(或森林)中。在要求自包含和自描述的结果是它们非常有用:

table_to_xml_and_xmlschema ( table regclass, nulls boolean,
                             tableforest boolean, targetns text ) → xml
query_to_xml_and_xmlschema ( query text, nulls boolean,
                             tableforest boolean, targetns text ) → xml

另外,下面的函数可用于产生相似的整个模式或整个当前数据库的映射:

schema_to_xml ( schema name, nulls boolean,
                tableforest boolean, targetns text ) → xml
schema_to_xmlschema ( schema name, nulls boolean,
                      tableforest boolean, targetns text ) → xml
schema_to_xml_and_xmlschema ( schema name, nulls boolean,
                              tableforest boolean, targetns text ) → xml

database_to_xml ( nulls boolean,
                  tableforest boolean, targetns text ) → xml
database_to_xmlschema ( nulls boolean,
                        tableforest boolean, targetns text ) → xml
database_to_xml_and_xmlschema ( nulls boolean,
                                tableforest boolean, targetns text ) → xml

这些函数会忽略当前用户不可读的表。数据库范围的函数还会忽略当前用户没有 USAGE(查找)权限的模式。

请注意,这可能会产生大量数据,这些数据需要在内存中构建。 当请求大型模式或数据库的内容映射时,可能值得考虑单独映射表,甚至可能通过游标。

一个模式内容映射的结果看起来像这样:

<schemaname>

table1-mapping

table2-mapping

...

</schemaname>

其中一个表映射的格式取决于上文解释的 tableforest 参数。

一个数据库内容映射的结果看起来像这样:

<dbname>

<schema1name>
  ...
</schema1name>

<schema2name>
  ...
</schema2name>

...

</dbname>

其中的模式映射如上所述。

作为一个使用这些函数产生的输出的例子,下面的例子展示了一个 XSLT 样式表,它将 table_to_xml_and_xmlschema 的输出转换为一个包含表数据的扁平转印的 HTML 文档。以一种相似的方式,这些函数的结果可以被转换成其他基于 XML 的格式。

转换 SQL/XML 输出到 HTML 的 XSLT 样式表

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.w3.org/1999/xhtml"
>

  <xsl:output method="xml"
      doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
      doctype-public="-//W3C/DTD XHTML 1.0 Strict//EN"
      indent="yes"/>

  <xsl:template match="/*">
    <xsl:variable name="schema" select="//xsd:schema"/>
    <xsl:variable name="tabletypename"
                  select="$schema/xsd:element[@name=name(current())]/@type"/>
    <xsl:variable name="rowtypename"
                  select="$schema/xsd:complexType[@name=$tabletypename]/xsd:sequence/xsd:element[@name='row']/@type"/>

    <html>
      <head>
        <title><xsl:value-of select="name(current())"/></title>
      </head>
      <body>
        <table>
          <tr>
            <xsl:for-each select="$schema/xsd:complexType[@name=$rowtypename]/xsd:sequence/xsd:element/@name">
              <th><xsl:value-of select="."/></th>
            </xsl:for-each>
          </tr>

          <xsl:for-each select="row">
            <tr>
              <xsl:for-each select="*">
                <td><xsl:value-of select="."/></td>
              </xsl:for-each>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

函数和操作符

处理和创建 JSON 数据

下表展示了可以用于 JSON 数据类型的操作符。

jsonjsonb 操作符

操作符描述例子
json -> integerjson``jsonb -> integerjsonb 提取 JSON 数组的第 n 个元素(数组元素从 0 开始索引,但负整数从末尾开始计数)。'[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> 2{"c":"baz"}``'[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> -3{"a":"foo"}
json -> textjson``jsonb -> textjsonb 用给定的键提取 JSON 对象字段。'{"a": {"b":"foo"}}'::json -> 'a'{"b":"foo"}
json ->> integertext``jsonb ->> integertext提取 JSON 数组的第 n 个元素,作为 text'[1,2,3]'::json ->> 23
json ->> texttext``jsonb ->> texttext 用给定的键提取 JSON 对象字段,作为 text'{"a":1,"b":2}'::json ->> 'b'2
json #> text[]json``jsonb #> text[]jsonb 提取指定路径下的 JSON 子对象,路径元素可以是字段键或数组索引。'{"a": {"b": ["foo","bar"]}}'::json #> '{a,b,1}'"bar"
json #>> text[]text``jsonb #>> text[]text 将指定路径上的 JSON 子对象提取为 text'{"a": {"b": ["foo","bar"]}}'::json #>> '{a,b,1}'bar

注意

如果 JSON 输入没有匹配请求的正确结构,字段/元素/路径提取操作符返回 NULL,而不是失败;例如,如果不存在这样的键或数组元素。

还有一些操作符仅适用于 jsonb,如下表所示。

附加的 jsonb 操作符

操作符描述例子
jsonb @> jsonbboolean 第一个 JSON 值是否包含第二个?'{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonbt
jsonb <@ jsonbboolean 第二个 JSON 中是否包含第一个 JSON 值?'{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonbt
jsonb ? textboolean 文本字符串是否作为 JSON 值中的顶级键或数组元素存在?'{"a":1, "b":2}'::jsonb ? 'b't``'["a", "b", "c"]'::jsonb ? 'b't
jsonb ?| text[]boolean 文本数组中的字符串是否作为顶级键或数组元素存在?'{"a":1, "b":2, "c":3}'::jsonb ?| array['b', 'd']t
jsonb ?& text[]boolean 文本数组中的所有字符串都作为顶级键或数组元素存在吗?'["a", "b", "c"]'::jsonb ?& array['a', 'b']t
jsonb || jsonbjsonb 连接两个 jsonb 值。连接两个数组将生成一个包含每个输入的所有元素的数组。连接两个对象将生成一个包含它们键的并集的对象,当存在重复的键时取第二个对象的值。 所有其他情况都是通过将非数组输入转换为单个元素数组,然后按照两个数组的方式进行处理。 不递归操作:只有顶级数组或对象结构被合并。'["a", "b"]'::jsonb || '["a", "d"]'::jsonb["a", "b", "a", "d"]``'{"a": "b"}'::jsonb || '{"c": "d"}'::jsonb{"a": "b", "c": "d"}
jsonb - textjsonb 从 JSON 对象中删除键(以及它的值),或从 JSON 数组中删除匹配的字符串值。'{"a": "b", "c": "d"}'::jsonb - 'a'{"c": "d"}``'["a", "b", "c", "b"]'::jsonb - 'b'["a", "c"]
jsonb - text[]jsonb 从左操作数中删除所有匹配的键或数组元素。'{"a": "b", "c": "d"}'::jsonb - '{a,c}'::text[]{}
jsonb - integerjsonb 删除具有指定索引的数组元素(负整数从末尾计数)。如果 JSON 值不是数组,则抛出错误。'["a", "b"]'::jsonb - 1["a"]
jsonb #- text[]jsonb 删除指定路径上的字段或数组元素,路径元素可以是字段键或数组索引。'["a", {"b":1}]'::jsonb #- '{1,b}'["a", {}]
jsonb @? jsonpathboolean JSON路径是否为指定的 JSON 值返回任何项?'{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)'t
jsonb @@ jsonpathboolean 返回指定 JSON 值的 JSON 路径谓词检查的结果。只考虑结果的第一项。如果结果不是布尔值,则返回 NULL'{"a":[1,2,3,4,5]}'::jsonb @@ '$.a[*] > 2't

注意

jsonpath 操作符 @?@@抑制以下错误:缺少对象字段或数组元素,意外的 JSON 项目类型,日期时间和数字错误。 还可以告诉以下描述的与 jsonpath 相关的函数来抑制这些类型的错误。在搜索不同结构的 JSON 文档集合时,此行为可能会有所帮助。 The jsonpath operators @? and @@ suppress the following errors: missing object field or array element, unexpected JSON item type, datetime and numeric errors. The jsonpath-related functions described below can also be told to suppress these types of errors. This behavior might be helpful when searching JSON document collections of varying structure.

下表显示可用于构造 jsonjsonb 值的函数。

JSON 创建函数

函数描述例子
to_json ( anyelement ) → json``to_jsonb ( anyelement ) → jsonb 将任何 SQL 值转换为 jsonjsonb。数组和组合递归地转换为数组和对象(多维数组在 JSON 中变成数组的数组)。 否则,如果存在从 SQL 数据类型到 json 的类型转换,则造型函数将用于执行转换; [a] 否则,将生成一个标量 json 值。对于除数字、布尔值或空值之外的任何标量,将使用文本表示,并根据需要进行转义,使其成为有效的 JSON 字符串值。to_json('Fred said "Hi."'::text)"Fred said \"Hi.\""``to_jsonb(row(42, 'Fred said "Hi."'::text)){"f1": 42, "f2": "Fred said \"Hi.\""}
array_to_json ( anyarray [, boolean ] ) → json 将 SQL 数组转换为 JSON 数组。该行为与 to_json 相同,只是如果可选 boolean 参数为真,换行符将在顶级数组元素之间添加。array_to_json('{{1,5},{99,100}}'::int[])[[1,5],[99,100]]
row_to_json ( record [, boolean ] ) → json 将 SQL 组合值转换为 JSON 对象。该行为与 to_json 相同,只是如果可选 boolean 参数为真,换行符将在顶级元素之间添加。row_to_json(row(1,'foo')){"f1":1,"f2":"foo"}
json_build_array ( VARIADIC "any" ) → json``jsonb_build_array ( VARIADIC "any" ) → jsonb 根据可变参数列表构建可能异构类型的 JSON 数组。每个参数都按照 to_jsonto_jsonb 进行转换。json_build_array(1, 2, 'foo', 4, 5)[1, 2, "foo", 4, 5]
json_build_object ( VARIADIC "any" ) → json``jsonb_build_object ( VARIADIC "any" ) → jsonb 根据可变参数列表构建一个 JSON 对象。按照惯例,参数列表由交替的键和值组成。 关键参数强制转换为文本;值参数按照 to_jsonto_jsonb 进行转换。json_build_object('foo', 1, 2, row(3,'bar')){"foo" : 1, "2" : {"f1":3,"f2":"bar"}}
json_object ( text[] ) → json``jsonb_object ( text[] ) → jsonb 从文本数组构建 JSON 对象。该数组必须有两个维度,一个维度的成员数为偶数,在这种情况下,它们被视为交替的键/值对; 另一个维度的成员数为二维,每个内部数组恰好有两个元素,它们被视为键/值对。所有值都转换为 JSON 字符串。json_object('{a, 1, b, "def", c, 3.5}'){"a" : "1", "b" : "def", "c" : "3.5"}``json_object('{{a, 1}, {b, "def"}, {c, 3.5}}'){"a" : "1", "b" : "def", "c" : "3.5"}
json_object ( keys text[], values text[] ) → json``jsonb_object ( keys text[], values text[] ) → jsonb 这种形式的 json_object 从单独的文本数组中成对地获取键和值。否则,它与单参数形式相同。json_object('{a,b}', '{1,2}'){"a": "1", "b": "2"}

下表显示可用于处理 jsonjsonb 值的函数。

JSON 处理函数

函数描述例子
json_array_elements ( json ) → setof json``jsonb_array_elements ( jsonb ) → setof jsonb 将顶级 JSON 数组展开为一组 JSON 值。SELECT * FROM json_array_elements('[1,true, [2,false]]') →``` value ----------- 1 true [2,false] `
json_array_elements_text ( json ) → setof text``jsonb_array_elements_text ( jsonb ) → setof text 将顶级 JSON 数组展开为一组文本值。SELECT * FROM json_array_elements_text('["foo", "bar"]') →``` value ----------- foo bar `
json_array_length ( json ) → integer``jsonb_array_length ( jsonb ) → integer 返回顶级 JSON 数组中的元素数量。json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]')5
json_each ( json ) → setof record ( key text, value json )jsonb_each ( jsonb ) → setof record ( key text, value jsonb ) 将顶级 JSON 对象展开为一组键/值对。SELECT * FROM json_each('{"a":"foo", "b":"bar"}') →``` keyvalue -----+------- a"foo" b"bar" `
json_each_text ( json ) → setof record ( key text, value text )jsonb_each_text ( jsonb ) → setof record ( key text, value text ) 将顶级 JSON 对象扩展为一组键/值对。返回的**的类型为文本SELECT * FROM json_each_text('{"a":"foo", "b":"bar"}') →``` keyvalue -----+------- afoo bbar `
json_extract_path ( from_json json, VARIADIC path_elems text[] ) → json``jsonb_extract_path ( from_json jsonb, VARIADIC path_elems text[] ) → jsonb 在指定路径下提取 JSON 子对象。(这在功能上相当于#>操作符,但在某些情况下,将路径写成可变参数列表会更方便。)json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6')"foo"
json_extract_path_text ( from_json json, VARIADIC path_elems text[] ) → text``jsonb_extract_path_text ( from_json jsonb, VARIADIC path_elems text[] ) → text 将指定路径上的 JSON 子对象提取为文本。(这在功能上等同于#>>操作符。)json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6')foo
json_object_keys ( json ) → setof text``jsonb_object_keys ( jsonb ) → setof text 返回顶级 JSON 对象中的键集合。SELECT * FROM json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}') →``` json_object_keys ------------------ f1 f2 `
json_populate_record ( base anyelement, from_json json ) → anyelement``jsonb_populate_record ( base anyelement, from_json jsonb ) → anyelement 将顶级 JSON 对象扩展为具有*基本参数的复合类型的行。JSON 对象将被扫描,查找名称与输出行类型的列名匹配的字段,并将它们的值插入到输出的这些列中。(不对应任何输出列名的字段将被忽略。)在典型的使用中,基本*的值仅为 NULL,这意味着任何不匹配任何对象字段的输出列都将被填充为空。 但是,如果 base 不为 NULL,那么它包含的值将用于不匹配的列。要将 JSON 值转换为输出列的 SQL 类型,需要按次序应用以下规则:在所有情况下,JSON 空值都会转换为 SQL 空值。如果输出列的类型是 jsonjsonb,则会精确地重制 JSON 值。如果输出列是复合(行)类型,且 JSON 值是 JSON 对象,则该对象的字段将转换为输出行类型的列,通过这些规则的递归应用程序。同样,如果输出列是数组类型,而 JSON 值是JSON 数组,则通过这些规则的递归应用程序将 JSON 数组的元素转换为输出数组的元素。否则,如果 JSON 值是字符串,则将字符串的内容提供给输入转换函数,用以确定列的数据类型。否则,JSON 值的普通文本表示将被提供给输入转换函数,以确定列的数据类型。虽然下面的示例使用一个常量 JSON 值,典型的用法是在查询的 FROM 子句中从另一个表侧面地引用 jsonjsonb 列。 在 FROM 子句中编写 json_populate_record 是一种很好的实践,因为提取的所有列都可以使用,而不需要重复的函数调用。create type subrowtype as (d int, e text); create type myrowtype as (a int, b text[], c subrowtype);``SELECT * FROM json_populate_record(null::myrowtype, '{"a": 1, "b": ["2", "a b"], "c": {"d": 4, "e": "a b c"}, "x": "foo"}') →``` abc ---+-----------+------------- 1{2,"a b"}(4,"a b c") `
json_populate_recordset ( base anyelement, from_json json ) → setof anyelement``jsonb_populate_recordset ( base anyelement, from_json jsonb ) → setof anyelement 将对象的顶级 JSON 数组展开为一组具有*基本*参数的复合类型的行。 对于 json[b]_populate_record,将如上所述处理 JSON 数组的每个元素。create type twoints as (a int, b int);``SELECT * FROM json_populate_recordset(null::twoints, '[{"a":1,"b":2}, {"a":3,"b":4}]') →``` ab ---+--- 12 34 `
json_to_record ( json ) → record``jsonb_to_record ( jsonb ) → record 将顶级 JSON 对象展开为具有由 AS 子句定义的复合类型的行。 (与所有返回 record 的函数一样,调用查询必须使用 AS 子句显式定义记录的结构。)输出记录由 JSON 对象的字段填充,与上面描述的 json[b]_populate_record 的方式相同。 由于没有输入记录值,不匹配的列总是用空值填充。create type myrowtype as (a int, b text);``SELECT * FROM json_to_record('{"a":1,"b":[1,2,3],"c":[1,2,3],"e":"bar","r": {"a": 123, "b": "a b c"}}') as x(a int, b text, c int[], d text, r myrowtype) →``` abcdr ---+---------+---------+---+--------------- 1[1,2,3]{1,2,3}(123,"a b c") `
json_to_recordset ( json ) → setof record``jsonb_to_recordset ( jsonb ) → setof record 将顶级 JSON 对象数组展开为一组由 AS 子句定义的复合类型的行。(与所有返回 record 的函数一样,调用查询必须使用 AS 子句显式定义记录的结构。) 对于 json[b]_populate_record,将如上所述处理 JSON 数组的每个元素。SELECT * FROM json_to_recordset('[{"a":1,"b":"foo"}, {"a":"2","c":"bar"}]') as x(a int, b text) →``` ab ---+----- 1foo 2`
jsonb_set ( target jsonb, path text[], new_value jsonb [, create_if_missing boolean ] ) → jsonb 返回 target,将 path 指定的项替换为 new_value, 如果 create_if_missing 为真(此为默认值)并且 path 指定的项不存在,则添加 new_value。 路径中的所有前面步骤都必须存在,否则将不加改变地返回 target。 与面向路径操作符一样,负整数出现在 JSON 数组末尾的 path 计数中。 如果最后一个路径步骤是超出范围的数组索引,并且 create_if_missing 为真,那么如果索引为负,新值将添加到数组的开头,如果索引为正,则添加到数组的结尾。jsonb_set('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', '[2,3,4]', false)[{"f1": [2, 3, 4], "f2": null}, 2, null, 3]``jsonb_set('[{"f1":1,"f2":null},2]', '{0,f3}', '[2,3,4]')[{"f1": 1, "f2": null, "f3": [2, 3, 4]}, 2]
jsonb_set_lax ( target jsonb, path text[], new_value jsonb [, create_if_missing boolean [, null_value_treatment text ]] ) → jsonb 如果 new_value 不为 NULL,则行为与 jsonb_set 完全一样。 否则,根据 null_value_treatment 的值,它必须是 'raise_exception''use_json_null''delete_key''return_target'。 默认值为'use_json_null'jsonb_set_lax('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', null)[{"f1":null,"f2":null},2,null,3]``jsonb_set_lax('[{"f1":99,"f2":null},2]', '{0,f3}', null, true, 'return_target')[{"f1": 99, "f2": null}, 2]
jsonb_insert ( target jsonb, path text[], new_value jsonb [, insert_after boolean ] ) → jsonb 返回插入 new_valuetarget。 如果 path 指派的项是一个数组元素,如果 insert_after 为假(此为默认值),则 new_value 将被插入到该项之前,如果 insert_after 为真则在该项之后。 如果由 path 指派的项是一个对象字段,则只在对象不包含该键时才插入 new_value。 路径中的所有前面步骤都必须存在,否则将不加改变地返回 target。 与面向路径操作符一样,负整数出现在 JSON 数组末尾的 path 计数中。 如果最后一个路径步骤是超出范围的数组下标,则如果下标为负,则将新值添加到数组的开头;如果下标为正,则将新值添加到数组的结尾。jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"'){"a": [0, "new_value", 1, 2]}``jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"', true){"a": [0, 1, "new_value", 2]}
json_strip_nulls ( json ) → json``jsonb_strip_nulls ( jsonb ) → jsonb 从给定的 JSON 值中删除所有具有空值的对象字段,递归地。非对象字段的空值是未受影响的。json_strip_nulls('[{"f1":1, "f2":null}, 2, null, 3]')[{"f1":1},2,null,3]
jsonb_path_exists ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean 检查 JSON 路径是否返回指定 JSON 值的任何项。如果指定了 vars 参数,则它必须是一个 JSON 对象,并且它的字段提供要替换到 jsonpath 表达式中的名称值。 如果指定了 silent 参数并为 true,函数会抑制与@?@@运算符相同的错误。jsonb_path_exists('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}')t
jsonb_path_match ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean 返回指定 JSON 值的 JSON 路径谓词检查的结果。只有结果的第一项被考虑在内。 如果结果不是布尔值,则返回 NULL。可选的 varssilent 参数的作用与 jsonb_path_exists 相同。jsonb_path_match('{"a":[1,2,3,4,5]}', 'exists($.a[*] ? (@ >= $min && @ <= $max))', '{"min":2, "max":4}')t
jsonb_path_query ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → setof jsonb 为指定的 JSON 值返回由 JSON 路径返回的所有 JSON 项。可选的 varssilent 参数的作用与 jsonb_path_exists 相同。SELECT * FROM jsonb_path_query('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}') →``` jsonb_path_query ------------------ 2 3 4 `
jsonb_path_query_array ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb 以 JSON 数组的形式返回由 JSON 路径为指定的 JSON 值返回的所有 JSON 项。可选的 varssilent 参数的作用与 jsonb_path_exists 相同。jsonb_path_query_array('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}')[2, 3, 4]
jsonb_path_query_first ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb 为指定的 JSON 值返回由 JSON 路径返回的第一个 JSON 项。如果没有结果则返回 NULL。 可选的 varssilent 参数的作用与 jsonb_path_exists 相同。jsonb_path_query_first('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}')2
jsonb_path_exists_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean``jsonb_path_match_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean``jsonb_path_query_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → setof jsonb``jsonb_path_query_array_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb``jsonb_path_query_first_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb 这些函数与上面描述的没有 _tz 后缀的对应函数类似,除了这些函数支持需要时区感知转换的日期/时间值比较之外。 下面的示例需要将只包含日期的值 2015-08-02 解释为带有时区的时间戳,因此结果依赖于当前 TimeZone 设置。 由于这种依赖性,这些函数被标记为稳定的,这意味着不能在索引中使用这些函数。 它们的对应项是不可改变的,因此可以用于索引;但是,如果要求他们进行这样的比较,他们就会抛出错误。jsonb_path_exists_tz('["2015-08-01 12:00:00 -05"]', '$[*] ? (@.datetime() < "2015-08-02".datetime())')t
jsonb_pretty ( jsonb ) → text 将给定的 JSON 值转换为精美打印的,缩进的文本。jsonb_pretty('[{"f1":1,"f2":null}, 2]') →```[ { "f1": 1, "f2": null }, 2 ] `
json_typeof ( json ) → text``jsonb_typeof ( jsonb ) → text 以文本字符串形式返回顶级 JSON 值的类型。可能的类型有object, array,string, number,booleannull。 (null 的结果不应该与 SQL NULL 混淆。)json_typeof('-123.4')number``json_typeof('null'::json)null``json_typeof(NULL::json) IS NULLt

SQL/JSON 路径语言

SQL/JSON 路径表达式指定了要从 JSON 数据中检索的项目,类似于 SQL 访问 XML 时使用的 XPath 表达式。

JSON 查询函数和操作符将提供的路径表达式传递给 path engine 进行评估。 如果表达式与被查询的 JSON 数据匹配,则返回相应的 JSON 项或项集。 路径表达式是用 SQL/JSON 路径语言编写的,也可以包括算术表达式和函数。

路径表达式由 jsonpath 数据类型允许的元素序列组成。路径表达式通常从左向右求值,但可以使用圆括号来更改操作的顺序。 如果计算成功,将生成一系列 JSON 项,并将计算结果返回到 JSON 查询函数,该函数将完成指定的计算。

要引用正在查询的 JSON 值(context item 项),在路径表达式中使用$变量。 它后面可以跟着一个或多个 accessor operators,这些操作符在 JSON 结构中逐级向下检索上下文项的子项。 后面的每个操作符处理前一个求值步骤的结果。

例如,假设有一些想要解析的来自 GPS 跟踪器的 JSON 数据,例如:

{
  "track": {
    "segments": [
      {
        "location":   [ 47.763, 13.4034 ],
        "start time": "2018-10-14 10:05:14",
        "HR": 73
      },
      {
        "location":   [ 47.706, 13.2635 ],
        "start time": "2018-10-14 10:39:21",
        "HR": 135
      }
    ]
  }
}

为了检索可用的轨迹段,需要使用.*key*访问操作符来向下浏览周边的 JSON 对象:

$.track.segments

要检索数组的内容,通常使用[*]操作符。例如,下面的路径将返回所有可用轨道段的位置坐标:

$.track.segments[*].location

要只返回第一个段的坐标,可以在[]访问操作符中指定相应的下标。重新调用相对于 0 的 JSON 数组索引:

$.track.segments[0].location

每个路径求值步骤的结果可以由一个或多个 jsonpath 操作符和方法来处理。 每个方法名之前必须有一个点。例如,可以得到一个数组的大小:

$.track.segments.size()

在路径表达式中使用 jsonpath 操作符和方法的更多示例见下面。

在定义路径时,还可以使用一个或多个与 SQL 中的 WHERE 子句类似的 filter expressions。 过滤器表达式以问号开头,并在圆括号中提供条件:

? (condition)

过滤表达式必须在它们应该应用的路径求值步骤之后写入。该步骤的结果将被筛选,以只包括满足所提供条件的那些项。 SQL/JSON 定义了三值逻辑,因此条件可以是 truefalseunknownunknown 值发挥与 SQL NULL 相同的角色,可以使用 is unknown 谓词进行测试。 进一步的路径求值步骤只使用筛选器表达式返回 true 的那些项。

在一个过滤表达式中,@变量表示被过滤的值(也就是说,前面路径步骤的一个结果)。可以在 @ 后面写访问操作符来检索组件项。

例如,假设想要检索所有高于 130 的心率值。可以使用下面的表达式来实现这一点:

$.track.segments[*].HR ? (@ > 130)

为了获得具有这些值的片段的开始时间,必须在返回开始时间之前过滤掉不相关的片段,所以过滤表达式应用于上一步,条件中使用的路径不同:

$.track.segments[*] ? (@.HR > 130)."start time"

如果需要,可以按顺序使用几个过滤器表达式。例如,下面的表达式选择所有包含有相关坐标和高心率值的位置的段的开始时间:

$.track.segments[*] ? (@.location[1] < 13.4) ? (@.HR > 130)."start time"

也允许在不同嵌套层级中使用过滤器表达式。下面的例子首先根据位置筛选所有的片段,然后返回这些片段的高心率值,如果适用的话:

$.track.segments[*] ? (@.location[1] < 13.4).HR ? (@ > 130)

也可以在彼此之间嵌套过滤器表达式:

$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()

如果包含任何具有高心率值的片段,则该表达式返回曲目的大小,否则返回空序列。

AntDB 的 SQL/JSON 路径语言的实现与 SQL/JSON 标准有以下偏差:

  • 路径表达式可以是布尔谓词,尽管 SQL/JSON 标准只允许在过滤器中使用谓词。 这是实现@@操作符所必需的。例如,下面的 jsonpath 表达式在 AntDB 中是有效的:

    $.track.segments[*].HR < 70
    
  • 在解释 like_regex 过滤器中使用的正则表达式模式方面有一些小的差异。

严格的(Strict) 和不严格的(Lax) 模式

当查询 JSON 数据时,路径表达式可能与实际的 JSON 数据结构不匹配。 试图访问不存在的对象成员或数组元素会导致结构错误。SQL/JSON 路径表达式有两种处理结构错误的模式:

  • 不严格的(lax)(默认)—路径引擎隐式地将查询的数据适配到指定的路径。任何剩余的结构错误都将被抑制并转换为空 SQL/JSON 序列。
  • 严格的(strict) —如果发生了结构错误,则会引发错误。

如果 JSON 数据不符合期望的模式,不严格的(lax)模式有助于匹配 JSON 文档结构和路径表达式。 如果操作不匹配特定操作的要求,可以自动将其包装为 SQL/JSON 数组,也可以在执行该操作之前将其元素转换为 SQL/JSON 序列来解包装。 此外,比较操作符会自动以 lax 模式打开它们的操作数,因此可以开包即用的就能比较 SQL/JSON 数组。 大小为 1 的数组被认为等于它的唯一元素。只有在以下情况下才不会自动展开:

  • 路径表达式包含 type()size() 方法,它们分别返回数组中的元素类型和数量。
  • 查询的 JSON 数据包含嵌套的数组。在本例中,只有最外层的数组被打开,而所有内部数组保持不变。 因此,隐式展开在每个路径求值步骤中只能向下进行一级。

例如,当查询上面列出的 GPS 数据时,当使用不严格的(lax)模式时,可以从它存储了一组片段的事实中抽象出来:

lax $.track.segments.location

在严格的(strict)模式中,指定的路径必须与查询的 JSON 文档的结构完全匹配才能返回 SQL/JSON 项,因此使用该路径表达式会导致错误。 要得到与不严格的(lax)模式相同的结果,必须显式地打开 segments数组:

strict $.track.segments[*].location

SQL/JSON 路径操作符和方法

下表显示了 jsonpath 中可用的操作符和方法。 请注意,虽然一元操作符和方法可以应用于由前一个路径步骤产生的多个值,二元操作符(加法等)只能应用于单个值。

jsonpath 操作符和方法

操作符/方法描述例子
number + number*number* 加法 jsonb_path_query('[2]', '$[0] + 3')5
+ number*number* 一元加号(无操作);与加法不同,这个可以迭代多个值 jsonb_path_query_array('{"x": [2,3,4]}', '+ $.x')[2, 3, 4]
number - number*number* 减法 jsonb_path_query('[2]', '7 - $[0]')5
- number*number* 否定;与减法不同,它可以迭代多个值 jsonb_path_query_array('{"x": [2,3,4]}', '- $.x')[-2, -3, -4]
number * number*number* 乘法 jsonb_path_query('[4]', '2 * $[0]')8
number / number*number* 除法 jsonb_path_query('[8.5]', '$[0] / 2')4.2500000000000000
number % number*number* 模数(余数)jsonb_path_query('[32]', '$[0] % 10')2
value . type()*string*JSON 项的类型(参见 json_typeofjsonb_path_query_array('[1, "2", {}]', '$[*].type()')["number", "string", "object"]
value . size()*number*JSON 项的大小(数组元素的数量,如果不是数组则为 1)jsonb_path_query('{"m": [11, 15]}', '$.m.size()')2
value . double()*number* 从 JSON 数字或字符串转换过来的近似浮点数 jsonb_path_query('{"len": "1.9"}', '$.len.double() * 2')3.8
number . ceiling()*number* 大于或等于给定数字的最接近的整数 jsonb_path_query('{"h": 1.3}', '$.h.ceiling()')2
number . floor()*number* 小于或等于给定数字的最近整数 jsonb_path_query('{"h": 1.7}', '$.h.floor()')1
number . abs()*number* 给定数字的绝对值 jsonb_path_query('{"z": -0.3}', '$.z.abs()')0.3
string . datetime()*datetime_type* (see note) 从字符串转换过来的日期/时间值 jsonb_path_query('["2015-8-1", "2015-08-12"]', '$[*] ? (@.datetime() < "2015-08-2".datetime())')"2015-8-1"
string . datetime(*template*)*datetime_type* (see note) 使用指定的 to_timestamp 模板从字符串转换过来的日期/时间值 jsonb_path_query_array('["12:30", "18:40"]', '$[*].datetime("HH24:MI")')["12:30:00", "18:40:00"]
object . keyvalue()*array* 对象的键值对,表示为包含三个字段的对象数组:"key""value""id""id" 是键值对所归属对象的唯一标识符 jsonb_path_query_array('{"x": "20", "y": 32}', '$.keyvalue()')[{"id": 0, "key": "x", "value": "20"}, {"id": 0, "key": "y", "value": 32}]

注意

datetime()datetime(*template*) 方法的结果类型可以是 datetimetztimetimestamptztimestamp。 这两个方法都动态地确定它们的结果类型。

datetime() 方法依次尝试将其输入字符串与 datetimetztimetimestamptztimestamp的 ISO 格式进行匹配。 它在第一个匹配格式时停止,并发出相应的数据类型。

datetime(*template*) 方法根据所提供的模板字符串中使用的字段确定结果类型。

datetime()datetime(*template*) 方法使用与 to_timestamp SQL 函数相同的解析规则,但有三个例外。 首先,这些方法不允许不匹配的模板模式。 其次,模板字符串中只允许以下分隔符:减号、句点、solidus(斜杠)、逗号、撇号、分号、冒号和空格。 第三,模板字符串中的分隔符必须与输入字符串完全匹配。

如果需要比较不同的日期/时间类型,则应用隐式转换。 date 值可以转换为 timestamptimestamptztimestamp 可以转换为 timestamptztime 可以转换为 timetz。 但是,除了第一个转换外,其他所有转换都依赖于当前 TimeZone 设置,因此只能在时区感知的 jsonpath 函数中执行。

下表显示了适用的过滤器表达式元素。

jsonpath 过滤器表达式元素

谓词/值描述例子
value == valueboolean 相等比较(这个和其他比较操作符,适用于所有 JSON 标量值)jsonb_path_query_array('[1, "a", 1, 3]', '$[*] ? (@ == 1)')[1, 1]``jsonb_path_query_array('[1, "a", 1, 3]', '$[*] ? (@ == "a")')["a"]
value != valuebooleanvalue <> valueboolean 不相等比较 jsonb_path_query_array('[1, 2, 1, 3]', '$[*] ? (@ != 1)')[2, 3]``jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ <> "b")')["a", "c"]
value < valueboolean 小于比较 jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ < 2)')[1]
value <= valueboolean 小于或等于比较 jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ <= "b")')["a", "b"]
value > valueboolean 大于比较 jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ > 2)')[3]
value >= valueboolean 大于或等于比较 jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ >= 2)')[2, 3]
trueboolean JSON 常数 真``jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == true)'){"name": "Chris", "parent": true}
falsebooleanJSON 常数 假``jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == false)'){"name": "John", "parent": false}
null*value* JSON 常数 null(注意,与 SQL 不同,与 null 比较可以正常工作)jsonb_path_query('[{"name": "Mary", "job": null}, {"name": "Michael", "job": "driver"}]', '$[*] ? (@.job == null) .name')"Mary"
boolean && booleanboolean 布尔 AND jsonb_path_query('[1, 3, 7]', '$[*] ? (@ > 1 && @ < 5)')3
boolean || booleanboolean 布尔 OR jsonb_path_query('[1, 3, 7]', '$[*] ? (@ < 1 || @ > 5)')7
! booleanboolean 布尔 NOT jsonb_path_query('[1, 3, 7]', '$[*] ? (!(@ < 5))')7
boolean is unknownboolean 测试布尔条件是否为 unknownjsonb_path_query('[-1, 2, 7, "foo"]', '$[*] ? ((@ > 0) is unknown)')"foo"
string like_regex string [ flag string ] → boolean 测试第一个操作数是否与第二个操作数给出的正则表达式匹配,可选使用由一串flag字符描述的修改。jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[*] ? (@ like_regex "^ab.*c")')["abc", "abdacb"]``jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[*] ? (@ like_regex "^ab.*c" flag "i")')["abc", "aBdC", "abdacb"]
string starts with stringboolean 测试第二个操作数是否为第一个操作数的初始子串。jsonb_path_query('["John Smith", "Mary Stone", "Bob Johnson"]', '$[*] ? (@ starts with "John")')"John Smith"
exists ( path_expression )boolean 测试路径表达式是否至少匹配一个 SQL/JSON 项。 如果路径表达式会导致错误,则返回 unknown;第二个例子使用这个方法来避免在严格模式下出现无此键(no-such-key)错误。jsonb_path_query('{"x": [1, 2], "y": [2, 4]}', 'strict $.* ? (exists (@ ? (@[*] > 2)))')[2, 4]``jsonb_path_query_array('{"value": 41}', 'strict $ ? (exists (@.name)) .name')[]

SQL/JSON 正则表达式

SQL/JSON 路径表达式允许通过 like_regex 过滤器将文本匹配为正则表达式。 例如,下面的 SQL/JSON 路径查询将不区分大小写地匹配以英语元音开头的数组中的所有字符串:

$[*] ? (@ like_regex "^[aeiou]" flag "i")

可选的 flag 字符串可以包括一个或多个字符 i 用于不区分大小写的匹配,m 允许^$在换行时匹配,s 允许.匹配换行符,q 引用整个模式(将行为简化为一个简单的子字符串匹配)。

SQL/JSON 标准借用了来自 LIKE_REGEX 操作符的正则表达式定义,其使用了 XQuery 标准。 AntDB 目前不支持 LIKE_REGEX 操作符。

请记住,like_regex 的模式参数是一个 JSON 路径字符串文字。 这特别意味着在正则表达式中要使用的任何反斜杠都必须加倍。例如,匹配只包含数字的字符串:

$ ? (@ like_regex "^\\d+$")

序列操作函数

本节描述对 sequence objects 进行操作的函数,也称为序列生成器或序列。 序列对象是使用 CREATE SEQUENCE 创建的特殊单行表。 序列对象通常用于为表中的行生成惟一标识符。下表中列出的序列函数,提供了简单的、多用户安全方法,用于从序列对象中获取连续的序列值。

序列函数

函数描述
nextval ( regclass ) → bigint 将序列对象推进到下一个值并返回该值。这是自动完成的:即使多个会话并发地执行 nextval,每个会话也会安全地接收到不同的序列值。 如果序列对象是用默认形参创建的,则连续的 nextval 调用将返回以 1 开始的连续值。 其他行为可以通过在 CREATE SEQUENCE 命令中使用适当的参数获得。这个函数需要 USAGEUPDATE 权限在序列上。
setval ( regclass, bigint [, boolean ] ) → bigint 设置序列对象的当前值,以及可选的它的 is_called 标志。 双参数形式将序列的 last_value 字段设置为指定的值,并将其 is_called 字段设置为 true,意味着下一个 nextval 将在返回值之前推进序列。 currval 将报告的值也设置为指定的值。在三参数形式中,is_called 可以设置为 truefalsetrue 与双参数形式具有相同的效果。 如果设置为 false,下一个 nextval 将返回指定的值,序列推进从下面的 nextval 开始。 而且,currval 报告的值在这种情况下不会改变。例如,SELECT setval('myseq', 42); *Nextnextvalwill return 43* SELECT setval('myseq', 42, true); *Same as above* SELECT setval('myseq', 42, false); *Nextnextvalwill return 42* ``setval 返回的结果就是它的第二个参数的值。这个函数在序列上需要 UPDATE 权限。
currval ( regclass ) → bigint 返回 nextval 在当前会话中为该序列最近获取的值。(如果在这个会话中没有为这个序列调用 nextval 会报告错误。) 因为它返回的是一个会话本地值,所以它给出了一个可预测的答案,即自当前会话以来,其他会话是否执行了 nextval。这个函数需要序列上的 USAGESELECT 权限。
lastval () → bigint 返回 nextval 在当前会话中最近返回的值。这个函数与 currval 相同,不同之处在于它没有使用序列名作为参数,而是引用当前会话中 nextval 最近应用到的序列。 如果在当前会话中还没有调用 nextval,那么调用 lastval 是一个错误。该函数在最后使用的序列上需要 USAGESELECT 权限。

小心

为了避免阻塞从相同序列中获取数字的并发事务,nextval 操作永远不会回滚;也就是说,一旦获取了一个值,它就会被认为是已使用的,并且不会再次返回。 即使周围的事务随后中止,或者调用查询最终没有使用该值,也会出现这种情况。 例如,带有 ON CONFLICT 子句的 INSERT 将计算要插入的元组,包括执行任何必需的 nextval 调用,在检测到任何可能导致它遵循 ON CONFLICT 规则的冲突之前。 这种情况会在赋值序列中留下未使用的“holes”。因此,AntDB 序列对象不能被用于获取 “gapless” 序列

同样的,如果事务回滚,setval 所做的任何序列状态更改都不会撤消。

序列函数所要操作的序列由 regclass 参数指定,该参数只是 pg_class 系统目录中序列的 OID。 不必手工查找 OID,不过,因为regclass 数据类型的输入转换器将完成这项工作。 只需将序列名用单引号括起来,这样它看起来就像一个文字常量。 为了与处理普通SQL名称兼容,字符串将被转换为小写,除非它在序列名称周围包含双引号。因此:

nextval('foo')      序列上操作 foo
nextval('FOO')      序列上操作 foo
nextval('"Foo"')    序列上操作 Foo

如需要,序列名称可以是模式限定的:

nextval('myschema.foo')     操作 myschema.foo
nextval('"myschema".foo')   同上
nextval('foo')              在搜索路径中查找 foo

注意

当把一个序列函数的参数写成一个无修饰的文字串,那么它将变成类型为 regclass 的常量。 因为这只是一个 OID,它将跟踪最初标识的序列,而不管后面是否改名、模式变化等等。 这种“早期绑定”的行为通常是列默认值和视图中引用的序列所需要的。 但是有时候可能想要“延迟绑定”,其中序列的引用是在运行时解析的。 要得到延迟绑定的行为,可以强制常量被存储为 text 常量,而不是regclass

nextval('foo'::text)      foo is looked up at runtime

请注意,延迟绑定是 AntDB 版本 8.1 之前唯一被支持的行为, 因此可能需要做这些来保留旧应用的语义。

当然,序列函数的参数也可以是表达式。如果它是一个文本表达式,那么隐式的转换将导致运行时的查找。

条件表达式

CASE

SQL CASE 表达式是一种通用的条件表达式,类似于其它编程语言中的 if/else 语句:

CASE WHEN condition THEN result
     [WHEN ...]
     [ELSE result]
END

CASE 子句可以用于任何表达式可以出现的地方。每一个 condition 是一个返回 boolean 结果的表达式。如果结果为真,那么 CASE 表达式的结果就是符合条件的 result,并且剩下的 CASE 表达式不会被处理。如果条件的结果不为真,那么以相同方式搜寻任何随后的 WHEN 子句。如果没有 WHEN condition 为真,那么 CASE 表达式的值就是在 ELSE 子句里的 result。如果省略了 ELSE 子句而且没有条件为真,结果为空。

例子:

SELECT * FROM test;

 a
---
 1
 2
 3


SELECT a,
       CASE WHEN a=1 THEN 'one'
            WHEN a=2 THEN 'two'
            ELSE 'other'
       END
    FROM test;

 a | case
---+-------
 1 | one
 2 | two
 3 | other

所有 result 表达式的数据类型都必须可以转换成单一的输出类型。

下面这个“简单”形式的 CASE 表达式是上述通用形式的一个变种:

CASE expression
    WHEN value THEN result
    [WHEN ...]
    [ELSE result]
END

第一个 expression 会被计算,然后与所有在 WHEN 子句中的每一个 value 对比,直到找到一个相等的。如果没有找到匹配的,则返回在 ELSE 子句中的 result(或者控制)。 这类似于 C 里的 switch 语句。

上面的例子可以用简单 CASE 语法来写:

SELECT a,
       CASE a WHEN 1 THEN 'one'
              WHEN 2 THEN 'two'
              ELSE 'other'
       END
    FROM test;

 a | case
---+-------
 1 | one
 2 | two
 3 | other

CASE 表达式并不计算任何无助于判断结果的子表达式。例如,下面是一个可以避免被零除错误的方法:

SELECT ... WHERE CASE WHEN x <> 0 THEN y/x > 1.5 ELSE false END;

注意

在有几种情况中一个表达式的子表达式 会被计算多次,因此“CASE只计算必要的表达式”这 一原则并非不可打破。例如一个常量子表达式 1/0 通常将会在规划时导致一次 除零错误,即便它位于一个执行时永远也不会进入的 CASE 分支时也是 如此。

COALESCE

COALESCE(value [, ...])

COALESCE 函数返回它的第一个非空参数的值。当且仅当所有参数都为空时才会返回空。它常用于在为显示目的检索数据时用缺省值替换空值。例如:

SELECT COALESCE(description, short_description, '(none)') ...

如果 description 不为空,这将会返回它的值,否则如果 short_description 非空则返回 short_description 的值,如果前两个都为空则返回(none)

所有参数都必须转换为一个公共数据类型,它将是结果的类型。

CASE 表达式一样,COALESCE 将不会计算无助于判断结果的参数;也就是说,在第一个非空参数右边的参数不会被计算。这个 SQL 标准函数提供了类似于 NVLIFNULL 的能力,它们被用在某些其他数据库系统中。

NULLIF

NULLIF(value1, value2)

value1value2 相等时,NULLIF 返回一个空值。 否则它返回 value1。 这些可以用于执行前文给出的 COALESCE 例子的逆操作:

SELECT NULLIF(value, '(none)') ...

在这个例子中,如果 value(none),将返回空值,否则返回 value 的值。

这两个参数必须具有可比较的类型。具体来说,它们的比较写的 *value1* = *value2* 完全一样,因此必须有一个合适的=操作符可用。

结果的类型与第一个参数相同,但有一点细微的区别。实际上返回的是隐含 =操作符的第一个参数,在某些情况下,它将被提升以匹配第二个参数的类型。 例如,NULLIF(1, 2.2) 生成 numeric,因为没有 integer = numeric 操作符,只有 numeric = numeric

GREATESTLEAST

GREATEST(value [, ...])
LEAST(value [, ...])

GREATESTLEAST 函数从一个任意的数字表达式列表里选取最大或者最小的数值。 这些表达式必须都可以转换成一个普通的数据类型,它将会是结果类型 。列表中的 NULL 数值将被忽略。只有所有表达式的结果都是 NULL 的时候,结果才会是 NULL。

请注意 GREATESTLEAST 都不是 SQL 标准,但却是很常见的扩展。某些其他数据库让它们在任何参数为 NULL 时返回 NULL,而不是在所有参数都为 NULL 时才返回 NULL。

数组函数和操作符

下表显示了可以用于数组类型的专用的操作符。比较操作符逐个元素的比较数组内容,使用默认的元素数据类型的 B-tree 比较函数,并根据第一个差值进行排序。 多维数组的元素按照行序进行访问(最后的下标变化最快)。 如果两个数组的内容相同但维数不等,那么维度信息中的第一个不同将决定排序顺序。

数组操作符

操作符描述例子
anyarray @> anyarrayboolean 第一个数组是否包含第二个数组,也就是说,出现在第二个数组中的每个元素是否等于第一个数组中的某个元素?(重复值不需要特殊处理,因此ARRAY[1]ARRAY[1,1]被认为包含对方。)ARRAY[1,4,3] @> ARRAY[3,1,3]t
anyarray <@ anyarrayboolean 第一个数组包含在第二个数组中么?ARRAY[2,2,7] <@ ARRAY[1,7,4,2,6]t
anyarray && anyarrayboolean 这些数组有重叠么,也就是说,它们有共同的元素么?ARRAY[1,4,3] && ARRAY[2,1]t
anyarray || anyarrayanyarray 连接两个数组。连接空(null)或空数组是一个无操作(no-op);否则,数组必须具有相同的维度数(如第一个示例所示),或者维度数相差一个(如第二个示例所示)。ARRAY[1,2,3] || ARRAY[4,5,6,7]{1,2,3,4,5,6,7}``ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9]]{{1,2,3},{4,5,6},{7,8,9}}
anyelement || anyarrayanyarray 将元素连接到数组的前面(数组必须为空或一维的 [one-dimensional])。3 || ARRAY[4,5,6]{3,4,5,6}
anyarray || anyelementanyarray 将元素连接到数组的末尾(数组必须为空或一维的[one-dimensional])。ARRAY[4,5,6] || 7{4,5,6,7}

数组函数

函数描述例子
array_append ( anyarray, anyelement ) → anyarray 向一个数组的末端追加一个元素 (等同于 anyarray || anyelement 操作符)。array_append(ARRAY[1,2], 3){1,2,3}
array_cat ( anyarray, anyarray ) → anyarray 连接两个数组(等同于 anyarray || anyarray 操作符)。array_cat(ARRAY[1,2,3], ARRAY[4,5]){1,2,3,4,5}
array_dims ( anyarray ) → text 返回数组维度的文本表示形式。array_dims(ARRAY[[1,2,3], [4,5,6]])[1:2][1:3]
array_fill ( anyelement, integer[] [, integer[] ] ) → anyarray 返回一个包含给定值的拷贝的数组,其维数与第二个参数指定的长度相同。 可选的第三个参数提供每个维度的下界值(默认为全部为 1)。array_fill(11, ARRAY[2,3]){{11,11,11},{11,11,11}}``array_fill(7, ARRAY[3], ARRAY[2])[2:4]={7,7,7}
array_length ( anyarray, integer ) → integer 返回请求的数组维度的长度。array_length(array[1,2,3], 1)3
array_lower ( anyarray, integer ) → integer 返回请求的数组维度的下界。array_lower('[0:2]={1,2,3}'::integer[], 1)0
array_ndims ( anyarray ) → integer 返回数组的维度数。array_ndims(ARRAY[[1,2,3], [4,5,6]])2
array_position ( anyarray, anyelement [, integer ] ) → integer 返回阵列中第二个参数中第一次发生的下标,如果它不存在,则返回 NULL。 如果给出了第三个参数,则搜索从该下标开始。数组必须是一维的。比较是使用 IS NOT DISTINCT FROM 语义进行的,所以可以搜索 NULLarray_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon')2
array_positions ( anyarray, anyelement ) → integer[] 返回作为第一个参数的数组中第二个参数所有出现的下标的数组。 数组必须是一维的。使用 IS NOT DISTINCT FROM 语义完成比较,所以可以搜索 NULL。 只有当数组为 NULL 时才返回 NULL;如果在数组中没有找到该值,则返回空数组。array_positions(ARRAY['A','A','B','A'], 'A'){1,2,4}
array_prepend ( anyelement, anyarray ) → anyarray 在数组的开头添加一个元素(等同于 anyelement || anyarray 操作符)。array_prepend(1, ARRAY[2,3]){1,2,3}
array_remove ( anyarray, anyelement ) → anyarray 从数组中移除与给定值相等的所有元素。数组必须是一维的。使用 IS NOT DISTINCT FROM 语义完成比较,所以可以删除 NULLarray_remove(ARRAY[1,2,3,2], 2){1,3}
array_replace ( anyarray, anyelement, anyelement ) → anyarray 将等于第二个参数的每个数组元素替换为第三个参数。array_replace(ARRAY[1,2,5,4], 5, 3){1,2,3,4}
array_to_string ( array anyarray, delimiter text [, null_string text ] ) → text 将每个数组元素转换为它的文本表现形式,并连接由 delimiter 符字符串分隔的元素。 如果给出了 null_string 且不为 NULL,则 NULL 数组项由该字符串表示;否则,它们将被省略。array_to_string(ARRAY[1, 2, 3, NULL, 5], ',', '*')1,2,3,*,5
array_upper ( anyarray, integer ) → integer 返回请求的数组维度的上界。array_upper(ARRAY[1,8,3,7], 1)4
cardinality ( anyarray ) → integer 返回数组中元素的总数,如果数组为空则返回 0。cardinality(ARRAY[[1,2],[3,4]])4
string_to_array ( string text, delimiter text [, null_string text ] ) → text[]在出现*分隔符时拆分字符串,并将剩余数据形成文本数组。 如果分隔符NULL,则字符串中的每个字符将成为数组中的单独元素。 如果分隔符为空字符串,则该字符串*视为单个字段。 如果提供了 null_string 且不为 NULL,那么匹配该字符串的字段将被转换为 NULL 项。string_to_array('xx~~yy~~zz', '~~', 'yy'){xx,NULL,zz}
unnest ( anyarray ) → setof anyelement 将数组展开为一组行。unnest(ARRAY[1,2]) →``` 1 2 `
unnest ( anyarray, anyarray [, ... ] ) → setof anyelement, anyelement [, ... ] 将多个数组(可能是不同的数据类型)展开为一组行。 如果数组的长度不完全相同,那么较短的数组将用 NULL 填充。 这只在查询的 FROM 子句中允许。SELECT * FROM unnest(ARRAY[1,2], ARRAY['foo','bar','baz']) as x(a,b) →``` ab ---+----- 1foo 2barbaz `

范围函数和运算符

下表显示了范围类型的专用操作符。除此之外,常用比较操作符也适用于范围类型。 比较操作符首先按范围下界排序,只有当它们相等时才比较上界。 这通常不会导致有用的总体排序,但提供的操作符允许在范围上构造惟一索引。

范围操作符

操作符描述例子
anyrange @> anyrangeboolean 第一个范围中包含第二个(范围)吗?int4range(2,4) @> int4range(2,3)t
anyrange @> anyelementboolean 范围是否包含元素?'[2011-01-01,2011-03-01)'::tsrange @> '2011-01-10'::timestampt
anyrange <@ anyrangeboolean 第一个范围包含在第二个(范围)吗?int4range(2,4) <@ int4range(1,7)t
anyelement <@ anyrangeboolean 元素是否包含在范围内?42 <@ int4range(1,7)f
anyrange && anyrangeboolean 范围是否重叠,也就是说,是否有相同的元素?int8range(3,7) && int8range(4,12)t
anyrange << anyrangeboolean 第一个范围是否严格地在第二个(范围)的左侧?int8range(1,10) << int8range(100,110)t
anyrange >> anyrangeboolean 第一个范围是否严格符合第二个(范围)?int8range(50,60) >> int8range(20,30)t
anyrange &< anyrangeboolean 第一个范围是否没有扩展到第二个(范围)的右侧?int8range(1,20) &< int8range(18,20)t
anyrange &> anyrangeboolean 第一个范围是否没有扩展到第二个(范围的)左侧?int8range(7,20) &> int8range(5,10)t
anyrange -|- anyrangeboolean 范围是相邻的么?numrange(1.1,2.2) -|- numrange(2.2,3.3)t
anyrange + anyrangeanyrange 计算范围的并集。范围必须重叠或相邻,这样的并集就是一个单一的范围(请参见range_merge())。numrange(5,15) + numrange(10,20)[5,20)
anyrange * anyrangeanyrange 计算范围的交集。int8range(5,15) * int8range(10,20)[10,15)
anyrange - anyrangeanyrange 计算范围的差异。第二个范围必须不能包含在第一个(范围)中,以使差异不是一个单一的范围。int8range(5,15) - int8range(10,20)[5,10)

当涉及一个空范围时,左部/右部/相邻操作符总是返回假;即一个空范围被认为不在任何其他范围前面或者后面。

下表显示可用于范围类型的函数。

范围函数

函数描述例子
lower ( anyrange ) → anyelement 提取范围的下界(如果范围为空或下界为无限,则为 NULL)。lower(numrange(1.1,2.2))1.1
upper ( anyrange ) → anyelement 提取范围的上限(如果范围为空或上限为无限,则为 NULL)。upper(numrange(1.1,2.2))2.2
isempty ( anyrange ) → boolean 范围为空吗?isempty(numrange(1.1,2.2))f
lower_inc ( anyrange ) → boolean 范围的下界是否包含在内?lower_inc(numrange(1.1,2.2))t
upper_inc ( anyrange ) → boolean 范围的上界是否包含在内?upper_inc(numrange(1.1,2.2))f
lower_inf ( anyrange ) → boolean 范围的下界是无限的吗?lower_inf('(,)'::daterange)t
upper_inf ( anyrange ) → boolean 范围的上界是无限的吗?upper_inf('(,)'::daterange)t
range_merge ( anyrange, anyrange ) → anyrange 计算包含两个给定范围的最小范围。range_merge('[1,2)'::int4range, '[3,4)'::int4range)[1,4)

lower_incupper_inclower_infupper_inf 函数对空范围(empty range)都返回假(false)。

聚集函数

聚集函数从一个输入值的集合计算出一个单一值。 内建的通用聚集函数、统计性聚集、内建的组内有序集聚集函数、内建的组内假想集聚集函数、聚集函数紧密相关的分组操作在下面的表中逐一列出。

支持部分模式的聚合函数具备参与各种优化的条件,例如并行聚合。

通用聚集函数

函数描述部分模式
array_agg ( anynonarray ) → anyarray 将所有输入值,包括空值,收集到一个数组中。No
array_agg ( anyarray ) → anyarray将所有输入数组连接到一个更高维度的数组中。(输入必须都具有相同的维度,并且不能为空的(empty)或空值(null)。)No
avg ( smallint ) → numeric``avg ( integer ) → numeric``avg ( bigint ) → numeric``avg ( numeric ) → numeric``avg ( real ) → double precision``avg ( double precision ) → double precision``avg ( interval ) → interval 计算所有非空输入值的平均值(算术平均值)。Yes
bit_and ( smallint ) → smallint``bit_and ( integer ) → integer``bit_and ( bigint ) → bigint``bit_and ( bit ) → bit 计算所有非空输入值的逐位 AND。Yes
bit_or ( smallint ) → smallint``bit_or ( integer ) → integer``bit_or ( bigint ) → bigint``bit_or ( bit ) → bit 计算所有非空输入值的逐位 OR。Yes
bool_and ( boolean ) → boolean 如果全部非空输入值都为真则返回真,否则返回假。Yes
bool_or ( boolean ) → boolean 如果任何非空输入值为真则返回真,否则返回假。Yes
count ( * ) → bigint 计算输入行的数量。Yes
count ( "any" ) → bigint 计算输入值不为空的输入行的数量。Yes
every ( boolean ) → boolean 这是对应 bool_and 的 SQL 标准的等效物。Yes
json_agg ( anyelement ) → json``jsonb_agg ( anyelement ) → jsonb 收集所有输入值,包括空值,到一个 JSON 数组。根据 to_jsonto_jsonb 将值转换为 JSON。No
json_object_agg ( key "any", value "any" ) → json``jsonb_object_agg ( key "any", value "any" ) → jsonb 将所有键/值对收集到一个 JSON 对象中。关键参数强制转换为文本;值参数按照 to_jsonto_jsonb 进行转换。 值可以为空,但键不能(为空)。No
max ( see text ) → *same as input type* 计算非空输入值的最大值。适用于任何数字、字符串、日期/时间或 enum 类型, 以及 inetintervalmoneyoidpg_lsntid 和任何这些类型的数组。Yes
min ( see text ) → *same as input type* 计算非空输入值的最小值。可用于任何数字、字符串、日期/时间或 enum 类型, 以及inetintervalmoneyoidpg_lsntid和任何这些类型的数组。Yes
string_agg ( value text, delimiter text ) → text``string_agg ( value bytea, delimiter bytea ) → bytea 连接非空输入值到字符串中。第一个值之后的每个值前面都有相应的*分隔符(delimiter)*(如果它不为空)。No
sum ( smallint ) → bigint``sum ( integer ) → bigint``sum ( bigint ) → numeric``sum ( numeric ) → numeric``sum ( real ) → real``sum ( double precision ) → double precision``sum ( interval ) → interval``sum ( money ) → money 计算非空输入值的总和。Yes
xmlagg ( xml ) → xml 连接非空的 XML 输入值。No

应该注意的是,除了 count 之外,这些函数在没有选择行时返回空值。 特别地,行数的 sum 返回空(null),而不是预期的零, array_agg 在没有输入行时返回空(null)而不是空数组。 coalesce 函数可以在必要时用零或空数组代替空(null)。

聚合函数 array_aggjson_aggjsonb_aggjson_object_aggjsonb_object_aggstring_aggxmlagg,以及类似的用户定义的聚合函数,根据输入值的顺序产生富有意义的不同的结果值。 默认情况下,这种排序是不指定的,但可以通过在聚合调用中写入 ORDER BY 子句来控制。 或者,从排序的子查询提供输入值通常也可以。例如:

SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;

注意,如果外部查询级别包含其他处理,例如关联,则此方法可能会失败,因为这可能导致子查询的输出在计算聚合之前重新排序。

注意

布尔聚合 bool_andbool_or 对应于标准 SQL 聚合 everyanysome. AntDB 支持 every, 但不支持 anysome, 因为标准语法中存在模糊性:

SELECT b1 = ANY((SELECT b2 FROM t2 ...)) FROM t1 ...;

这里 ANY 可以被认为是引入子查询,或者是聚合函数,如果子查询返回一行布尔值。因此,不能为这些聚合提供标准名称。

注意

习惯使用其他 SQL 数据库管理系统的用户可能会对 count 聚合应用于整个表时的性能感到失望。一个类似下面的查询:

SELECT count(*) FROM sometable;

将需要与表大小成比例的工作:AntDB 将需要扫描整个表或包含表中所有行的索引。

下表显示了统计分析中常用的聚合函数。(这些被分离出来仅仅是为了避免使更常用的聚合列表混乱。)显示为接受 numeric_type 的函数可用于所有类型 smallintintegerbigintnumericrealdouble precision。在描述中提及 N 时,它意味着所有输入表达式都非空的输入行数。在所有情况下,如果计算没有意义,则返回 null,例如当 N 为 0 时。

用于统计的聚集函数

函数描述部分模式
corr ( Y double precision, X double precision ) → double precision 计算相关系数。Yes
covar_pop ( Y double precision, X double precision ) → double precision 计算总体协方差。Yes
covar_samp ( Y double precision, X double precision ) → double precision 计算样本协方差。Yes
regr_avgx ( Y double precision, X double precision ) → double precision 计算自变量的平均值,sum(*X*)/*N*.Yes
regr_avgy ( Y double precision, X double precision ) → double precision 计算因变量的平均值,sum(*Y*)/*N*.Yes
regr_count ( Y double precision, X double precision ) → bigint 计算两个输入都非空的行数。Yes
regr_intercept ( Y double precision, X double precision ) → double precision 计算由(XY)对决定的最小二乘拟合的线性方程的 Y- 截距。Yes
regr_r2 ( Y double precision, X double precision ) → double precision 计算相关系数的平方。Yes
regr_slope ( Y double precision, X double precision ) → double precision 计算由(X, Y)对决定的最小二乘拟合的线性方程的斜率。Yes
regr_sxx ( Y double precision, X double precision ) → double precision 计算自变量的“平方和” sum(*X*^2) - sum(*X*)^2/*N*.Yes
regr_sxy ( Y double precision, X double precision ) → double precision 计算独立变量乘以因变量的“sum of products”, sum(*X***Y*) - sum(*X*) * sum(*Y*)/*N*.Yes
regr_syy ( Y double precision, X double precision ) → double precision 计算因变量的“平方和”, sum(*Y*^2) - sum(*Y*)^2/*N*.Yes
stddev ( numeric_type ) → ```double precisionforrealordouble precision, otherwisenumeric这是stddev_samp` 的一个历史别称。Yes
stddev_pop ( numeric_type ) → ```double precisionforrealordouble precision, otherwisenumeric` 计算输入值的总体标准差。Yes
stddev_samp ( numeric_type ) → ```double precisionforrealordouble precision, otherwisenumeric` 计算输入值的样本标准差。Yes
variance ( numeric_type ) → ```double precisionforrealordouble precision, otherwisenumeric这是var_samp` 的一个历史别称。Yes
var_pop ( numeric_type ) → ```double precisionforrealordouble precision, otherwisenumeric` 计算输入值的总体方差(总体标准差的平方)。Yes
var_samp ( numeric_type ) → ```double precisionforrealordouble precision, otherwisenumeric` 计算输入值的样本方差(样本标准差的平方)。Yes

下表显示了一些使用 ordered-set aggregate 语法的聚合函数。 这些函数有时被称为“inverse distribution”函数。 它们的聚合输入是通过 ORDER BY 引入的,它们还可以接受未聚合的 direct argument,但只计算一次。 所有这些函数在其聚合的输入中都忽略空(null)值。 对于使用 fraction(fraction) 参数的函数,分数值必须在 0 到 1 之间;否则将抛出一个错误。但是,空*分数*值简单地产生一个空结果。

有序集聚集函数

函数描述部分模式
mode () WITHIN GROUP ( ORDER BY anyelement ) → anyelement 计算 mode,即聚合参数最频繁的值(如果有多个相同频繁的值,第一个可以任意选择)。聚合参数必须是可排序类型。No
percentile_cont ( fraction double precision ) WITHIN GROUP ( ORDER BY double precision ) → double precision``percentile_cont ( fraction double precision ) WITHIN GROUP ( ORDER BY interval ) → interval 计算 continuous percentile,该值对应于聚合参数值的有序集合中的指定*分数(fraction)*。 如果需要,这将在相邻的输入项之间插入。No
percentile_cont ( fractions double precision[] ) WITHIN GROUP ( ORDER BY double precision ) → double precision[]``percentile_cont ( fractions double precision[] ) WITHIN GROUP ( ORDER BY interval ) → interval[] 计算多个连续的百分位数。结果是一个与*分数(fractions)*参数具有相同维数的数组,每个非空元素都被对应于该百分位的(可能插值的)值所替换。No
percentile_disc ( fraction double precision ) WITHIN GROUP ( ORDER BY anyelement ) → anyelement 计算离散百分比(discrete percentile),即聚合参数值的有序集合中的第一个值,该值在排序中的位置等于或超过指定的 fraction。 聚合参数必须是可排序类型。No
percentile_disc ( fractions double precision[] ) WITHIN GROUP ( ORDER BY anyelement ) → anyarray 计算多个离散百分位数。 结果是一个与 fractions 参数具有相同维数的数组,每个非空元素都被对应于该百分位的输入值替换。 聚合参数必须是可排序类型。No

在每种情况下,聚合的结果都是相关的窗口函数将为由 args 构造的“hypothetical”行返回的值,如果将这样的行添加到 sorted_args 表示的已排序行组中。 对于这些函数中的每一个,args 中给出的直接参数列表必须与 sorted_args 中给出的聚合参数的数量和类型匹配。 与大多数内置聚合不同,这些聚合不是严格的,也就是说它们不会删除包含空值的输入行。空值根据 ORDER BY 子句中指定的规则排序。

假想集聚集函数

函数描述部分模式
rank ( args ) WITHIN GROUP ( ORDER BY sorted_args ) → bigint 计算假设行的排名,包括间隔,就是说在它的对等组中第一行的行号。No
dense_rank ( args ) WITHIN GROUP ( ORDER BY sorted_args ) → bigint 计算假设行的排名,没有间隔;这个功能有效地计数对等组。No
percent_rank ( args ) WITHIN GROUP ( ORDER BY sorted_args ) → double precision 计算假设行的相关排行,也就是 (rank - 1) / (total rows - 1)。取值范围为 0 到 1(含)。No
cume_dist ( args ) WITHIN GROUP ( ORDER BY sorted_args ) → double precision 计算累积分布,也就是(前面或具有假设行的对等行数)/(总行数)。取值范围为 1/N 到 1。No

分组操作

函数描述
GROUPING ( group_by_expression(s) ) → integer 返回一个位掩码以指示哪个 GROUP BY 表达式没有包含在当前分组集中。 比特位被分配给最右边的参数对应于最低有效位;如果对应的表达式包含在生成当前结果行的分组集的分组条件中,则每个位为 0,如果不包含则为 1。

上表所示的分组操作与分组集共同使用,以区分结果行。 GROUPING 函数的参数实际上并不求值,但它们必须与相关查询级别的 GROUP BY 子句中给出的表达式完全匹配。例如:

=> SELECT * FROM items_sold;
 make  | model | sales
-------+-------+-------
 Foo   | GT    |  10
 Foo   | Tour  |  20
 Bar   | City  |  15
 Bar   | Sport |  5
(4 rows)

=> SELECT make, model, GROUPING(make,model), sum(sales) FROM items_sold GROUP BY ROLLUP(make,model);
 make  | model | grouping | sum
-------+-------+----------+-----
 Foo   | GT    |        0 | 10
 Foo   | Tour  |        0 | 20
 Bar   | City  |        0 | 15
 Bar   | Sport |        0 | 5
 Foo   |       |        1 | 30
 Bar   |       |        1 | 20
       |       |        3 | 50
(7 rows)

在这里,前四行中的 grouping0 表明这些已经正常分组,在两个分组列上。 值 1 表示 model 没有在倒数两行中分组,值 3 表示无论是 make 还是 model 都没有在最后一行中分组(因此,这是所有输入行的聚合)。

窗口函数

Window functions 提供了跨越与当前查询行相关的行集执行计算的能力。

内置的窗口函数罗列在下表中。注意,这些函数必须使用窗口函数语法来调用,也就是说,需要一个 OVER 子句。

除了这些函数之外,任何内置的或用户定义的普通聚合(例如非有序集或假设集聚合)都可以作为窗口函数使用;关于内置聚合的列表。 聚合函数只有在调用之后有一个 OVER 子句时才作为窗口函数;否则,它们充当普通的聚合,并为整个集合返回一行。

通用窗口函数

函数描述
row_number () → bigint 返回其分区内的当前行数,从 1 开始计数。
rank () → bigint 返回当前行的排名,包含间隔;即对等组中第一行的 row_number
dense_rank () → bigint 返回当前行的排名,不包括间隔;这个功能有效地计数对等组。
percent_rank () → double precision 返回当前行的相对排名,即 (rank - 1) / (总的分区行数 - 1)。因此,该值的范围从 0 到 1(包含在内)。
cume_dist () → double precision 返回累积分布,也就是(当前行之前或对等的分区行数)/(总的分区行数)。取值范围为 1/N 到 1。
ntile ( num_buckets integer ) → integer 返回一个从 1 到参数值的整数,并将分区划分为尽可能相等的值。
lag ( value anyelement [, offset integer [, default anyelement ]] ) → anyelement 返回分区中在当前行之前 offset 行的 value ;如果没有这样的行,则返回 default (必须与 value 具有相同的类型)。 offsetdefault 都是针对当前行求值的。如果省略,offset 默认为 1,defaultNULL
lead ( value anyelement [, offset integer [, default anyelement ]] ) → anyelement 返回分区中在当前行之后 offset 行的 value; 如果没有这样的行,则返回 default(必须与 value 具有相同的类型)。 offsetdefault 都是针对当前行求值的。如果省略,offset 默认为 1,defaultNULL
first_value ( value anyelement ) → anyelement 返回在窗口框架的第一行求得的 value
last_value ( value anyelement ) → anyelement 返回在窗口框架的最后一行求得的 value
nth_value ( value anyelement, n integer ) → anyelement 返回在窗口框架的第 n 行求得的 value(从 1 开始计数);如果没有这样的行,则返回 NULL

注意 first_valuelast_valuenth_value 只考虑“窗口帧”内的行,它默认情况下包含从分区的开始行直到当前行的最后一个同等行。 这对 last_value 可能不会给出有用的结果,有时对 nth_value 也一样。 可以通过向 OVER 子句增加一个合适的帧声明(RANGEGROUPS)来重定义帧。

当一个聚集函数被用作窗口函数时,它将在当前行的窗口帧内的行上聚集。 一个使用 ORDER BY 和默认窗口帧定义的聚集产生一种“运行时求和”类型的行为,这可能是或者不是想要的结果。 为了获取在整个分区上的聚集,忽略 ORDER BY 或者使用 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING。 其它窗口帧声明可以用来获得其它的效果。

注意

SQL 标准为 leadlagfirst_valuelast_valuenth_value 定义了一个 RESPECT NULLSIGNORE NULLS 选项。 这在 AntDB 中没有实现:行为总是与标准的默认相同,即 RESPECT NULLS。 同样,标准中用于 nth_valueFROM FIRSTFROM LAST 选项没有实现:只有支持默认的 FROM FIRST 行为(可以通过反转 ORDER BY 的排序达到 FROM LAST 的结果)。

子查询表达式

EXISTS

EXISTS (subquery)

EXISTS 的参数是一个任意的 SELECT 语句, 或者说子查询。系统对子查询进行运算以判断它是否返回行。如果它至少返回一行,那么EXISTS 的结果就为“真”; 如果子查询没有返回行,那么 EXISTS 的结果是“假”。

子查询可以引用来自周围的查询的变量,这些变量在该子查询的任何一次计算中都起常量的作用。

这个子查询通常只是运行到能判断它是否可以返回至少一行为止, 而不是等到全部结束。在这里写任何有副作用的子查询都是不明智的(例如调用序列函数);这些副作用是否发生是很难判断的。

因为结果只取决于是否会返回行,而不取决于这些行的内容, 所以这个子查询的输出列表通常是无关紧要的。一个常用的编码习惯是用EXISTS(SELECT 1 WHERE ...)的形式写所有的 EXISTS 测试。不过这条规则有例外,例如那些使用 INTERSECT 的子查询。

下面这个简单的例子类似在 col2 上的一次内联接,但是它为每个 tab1 的行生成最多一个输出,即使存在多个匹配 tab2 的行也如此∶

SELECT col1
FROM tab1
WHERE EXISTS (SELECT 1 FROM tab2 WHERE col2 = tab1.col2);

IN

expression IN (subquery)

右手边是一个圆括弧括起来的子查询, 它必须正好只返回一个列。左手边表达式将被计算并与子查询结果逐行进行比较。 如果找到任何等于子查询行的情况,那么 IN 的结果就是“真”。 如果没有找到相等行,那么结果是“假”(包括子查询没有返回任何行的情况)。

请注意如果左手边表达式得到空值,或者没有相等的右手边值, 并且至少有一个右手边行得到空值,那么 IN 结构的结果将是空值,而不是假。这个行为是遵照 SQL 处理空值的一般规则的。

EXISTS 一样,假设子查询将被完成运行完全是不明智的。

row_constructor IN (subquery)

这种形式的 IN 的左手边是一个行构造器。 右手边是一个圆括弧子查询,它必须返回和左手边返回的行中表达式所构成的完全一样多的列。 左手边表达式将被计算并与子查询结果逐行进行比较。如果找到任意相等的子查询行,则 IN 的结果为“真”。如果没有找到相等行, 那么结果为“假”(包括子查询不返回行的情况)。

通常,表达式或者子查询行里的空值是按照 SQL 布尔表达式的一般规则进行组合的。 如果两个行对应的成员都非空并且相等,那么认为这两行相等;如果任意对应成员为非空且不等,那么这两行不等; 否则这样的行比较的结果是未知(空值)。如果所有行的结果要么是不等, 要么是空值,并且至少有一个空值,那么 IN 的结果是空值。

NOT IN

expression NOT IN (subquery)

右手边是一个用圆括弧包围的子查询,它必须返回正好一个列。左手边表达式将被计算并与子查询结果逐行进行比较。 如果只找到不相等的子查询行(包括子查询不返回行的情况),那么 NOT IN 的结果是“真”。 如果找到任何相等行,则结果为“假”。

请注意如果左手边表达式得到空值,或者没有相等的右手边值, 并且至少有一个右手边行得到空值,那么 NOT IN 结构的结果将是空值,而不是真。这个行为是遵照 SQL 处理空值的一般规则的。

EXISTS 一样,假设子查询会完全结束是不明智的。

row_constructor NOT IN (subquery)

这种形式的 NOT IN 的左手边是一个行构造器。 右手边是一个圆括弧子查询,它必须返回和左手边返回的行中表达式所构成的完全一样多的列。 左手边表达式将被计算并与子查询结果逐行进行比较。如果找到不等于子查询行的行,则 NOT IN 的结果为“真”。如果找到相等行, 那么结果为“假”(包括子查询不返回行的情况)。

通常,表达式或者子查询行里的空值是按照 SQL 布尔表达式的一般规则进行组合的。 如果两个行对应的成员都非空并且相等,那么认为这两行相等;如果任意对应成员为非空且不等,那么这两行不等; 否则这样的行比较的结果是未知(空值)。如果所有行的结果要么是不等, 要么是空值,并且至少有一个空值,那么 NOT IN 的结果是空值。

ANY/SOME

expression operator ANY (subquery)
expression operator SOME (subquery)

这种形式的右手边是一个圆括弧括起来的子查询, 它必须返回正好一个列。左手边表达式将被计算并使用给出的 *操作符*对子查询结果逐行进行比较。如果获得任何真值结果,那么 ANY 的结果就是“真”。 如果没有找到真值结果,那么结果是“假”(包括子查询没有返回任何行的情况)。

SOMEANY 的同义词。IN 等价于 = ANY

请注意如果没有任何成功并且至少有一个右手边行为该操作符结果生成空值, 那么 ANY 结构的结果将是空值,而不是假。 这个行为是遵照 SQL 处理空值布尔组合的一般规则制定的。

EXISTS 一样,假设子查询将被完全运行是不明智的。

row_constructor operator ANY (subquery)
row_constructor operator SOME (subquery)

这种形式的左手边是一个行构造器。右手边是一个圆括弧括起来的子查询, 它必须返回和左手边列表给出的表达式一样多的列。左手边表达式将被计算并使用给出的*操作符*对子查询结果逐行进行比较。如果比较为任何子查询行返回真,则 ANY 的结果为“真”。如果比较对每一个子查询行都返回假,则结果为“假”(包括子查询不返回行的情况)。如果比较不对任何行返回真并且至少对一行返回 NULL,则结果为 NULL。

ALL

expression operator ALL (subquery)

ALL 的这种形式的右手边是一个圆括弧括起来的子查询, 它必须只返回一列。左手边表达式将被计算并使用给出的 *操作符*对子查询结果逐行进行比较。该操作符必须生成布尔结果。 如果所有行得到真(包括子查询没有返回任何行的情况),ALL 的结果就是“真”。如果没有存在任何假值结果,那么结果是“假”。如果比较为任何行都不返回假并且对至少一行返回 NULL,则结果为 NULL。

NOT IN 等价于 <> ALL

EXISTS 一样,假设子查询将被完全运行是不明智的。

row_constructor operator ALL (subquery)

ALL 的这种形式的左手边是一个行构造器。 右手边是一个圆括弧括起来的子查询,它必须返回和左手边行中表达式一样多的列。 左手边表达式将被计算并使用给出的 *操作符*对子查询结果逐行进行比较。如果对所有子查询行该比较都返回真,那么 ALL 的结果就是“真”(包括子查询没有返回任何行的情况)。如果对任何子查询行比较返回假,则结果为“假”。如果比较对任何子查询行都不返回假并且对至少一行返回 NULL,则结果为 NULL。

单一行比较

row_constructor operator (subquery)

左手边是一个行构造器。 右手边是一个圆括弧括起来的子查询,该查询必须返回和左手边行中表达式数目完全一样的列。 另外,该子查询不能返回超过一行的数量(如果它返回零行,那么结果就是空值)。 左手边被计算并逐行与右手边的子查询结果行比较。

行和数组比较

本节描述几个特殊的结构,用于在值的组之间进行多重比较。这些形式语法上和前面一节的子查询形式相关,但是不涉及子查询。 这种形式涉及的数组子表达式是 AntDB 的扩展; 其它的是 SQL 兼容的。所有本节记录的表达式形式都返回布尔(Boolean)结果(真/假)。

IN

expression IN (value [, ...])

右手边是一个圆括弧包围的标量列表。如果左手边表达式的结果等于任何右手边表达式中的一个,结果为“真”。它是下面形式的缩写

expression = value1
OR
expression = value2
OR
...

请注意如果左手边表达式得到空值,或者没有相等的右手边值并且至少有一个右手边的表达式得到空值,那么 IN 结构的结果将为空值,而不是假。这符合 SQL 处理空值的布尔组合的一般规则。

NOT IN

expression NOT IN (value [, ...])

右手边是一个圆括弧包围的标量列表。如果左手边表达式的结果不等于所有右手边表达式,结果为“真”。它是下面形式的缩写

expression <> value1
AND
expression <> value2
AND
...

请注意如果左手边表达式得到空值,或者没有相等的右手边值并且至少有一个右手边的表达式得到空值,那么 NOT IN 结构的结果将为空值, 而不是可能天真地认为的真值。这符合 SQL 处理空值的布尔组合的一般规则。

提示

x NOT IN y 在所有情况下都等效于 NOT (x IN y)。但是,在处理空值的时候,用 NOT IN 比用 IN 更可能迷惑新手。最好尽可能用正逻辑来表达条件。

ANY/SOME (array)

expression operator ANY (array expression)
expression operator SOME (array expression)

右手边是一个圆括弧包围的表达式,它必须得到一个数组值。左手边表达式被计算并且使用给出的*操作符*对数组的每个元素进行比较,这个操作符必须得到布尔结果。如果得到了任何真值结果,那么 ANY 的结果是“真”。 如果没有找到真值结果(包括数组只有零个元素的情况),那么结果是“假”。

如果数组表达式得到一个空数组,ANY 的结果将为空值。如果左手边的表达式得到空值,ANY 通常是空值(尽管一个非严格比较操作符可能得到一个不同的结果)。另外,如果右手边的数组包含任何空值元素或者没有得到真值比较结果,ANY 的结果将是空值而不是假(再次,假设是一个严格的比较操作符)。这符合 SQL 对空值的布尔组合的一般规则。

SOMEANY 的同义词。

ALL (array)

expression operator ALL (array expression)

右手边是一个圆括弧包围的表达式,它必须得到一个数组值。左手边表达式将被计算并使用给出的*操作符*与数组的每个元素进行比较,这个操作符必须得到一个布尔结果。如果所有比较都得到真值结果,那么 ALL 的结果是 “真”(包括数组只有零个元素的情况)。如果有任何假值结果,那么结果是“假”。

如果数组表达式得到一个空数组,ALL 的结果将为空值。如果左手边的表达式得到空值,ALL 通常是空值(尽管一个非严格比较操作符可能得到一个不同的结果)。另外,如果右手边的数组包含任何空值元素或者没有得到假值比较结果,ALL 的结果将是空值而不是真(再次,假设是一个严格的比较操作符)。这符合 SQL 对空值的布尔组合的一般规则。

行构造器比较

row_constructor operator row_constructor

每一边都是一个行构造器。两个行值必须具有相同数量的域。每一边被计算并且被逐行比较。当*操作符*是 =<>< <=>>=时,允许进行行构造器比较。每一个行元素必须是具有一个默认 B 树操作符类的类型,否则尝试比较会产生一个错误。

注意

Errors related to the number or types of elements might not occur if the comparison is resolved using earlier columns.

=<> 情况略有不同。如果两行的所有对应成员都是非空且相等则这两行被认为相等;如果任何对应成员是非空但是不相等则这两行不相等;否则行比较的结果为未知(空值)。

对于<<=>>=情况,行元素被从左至右比较,在找到一处不等的或为空的元素对就立刻停下来。如果这一对元素都为空值,则行比较的结果为未知(空值);否则这一对元素的比较结果决定行比较的结果。例如,ROW(1,2,NULL) < ROW(1,3,0) 得到真,而不是空值,因为第三对元素并没有被考虑。

注意

在 AntDB 8.2 之前,<<=>>= 情况不是按照每个 SQL 声明来处理的。一个像 ROW(a,b) < ROW(c,d) 的比较会被实现为 a < c AND b < d,而结果行为等价于 a < c OR (a = c AND b < d)

row_constructor IS DISTINCT FROM row_constructor

这个结构与 <> 行比较相似,但是它对于空值输入不会得到空值。任何空值被认为和任何非空值不相等(有区别),并且任意两个空值被认为相等(无区别)。因此结果将总是为真或为假,永远不会是空值。

row_constructor IS NOT DISTINCT FROM row_constructor

这个结构与=行比较相似,但是它对于空值输入不会得到空值。任何空值被认为和任何非空值不相等(有区别),并且任意两个空值被认为相等(无区别)。因此结果将总是为真或为假,永远不会是空值。

组合类型比较

record operator record

SQL 规范要求在结果依赖于比较两个 NULL 值或者一个 NULL 与一个非 NULL 时逐行比较返回 NULL。AntDB 只有在比较两个行构造器的结果或者比较一个行构造器与一个子查询的输出时才这样做。在其他比较两个组合类型值的环境中,两个 NULL 域值被认为相等,并且一个 NULL 被认为大于一个非 NULL。为了得到组合类型的一致的排序和索引行为,这样做是必要的。

每一边都会被计算并且它们会被逐行比较。当*操作符*是 =<><<=>或者 >=时或者具有与这些类似的语义时,允许组合类型的比较(更准确地说,如果一个操作符是一个 B 树操作符类的成员,或者是一个 B 树操作符类的=成员的否定词,它就可以是一个行比较操作符)。上述操作符的行为与用于行构造器的 IS [ NOT ] DISTINCT FROM 相同。

为了支持包含无默认 B 树操作符类的元素的行匹配,为组合类型比较定义了下列操作符: *=*<>*<*<=*>以及 *>=。 这些操作符比较两行的内部二进制表达。即使两行用相等操作符的比较为真,两行也可能具有不同的二进制表达。 行在这些比较操作符之下的排序是决定性的,其他倒没什么意义。 这些操作符在内部被用于物化视图并且可能对其他如复制和B-树复制之类的特殊功能有用,但是它们并不打算用在书写查询这类普通用途中。

集合返回函数

本节描述那些可能返回多于一行的函数。目前这个类中被使用最广泛的是级数生成函数。

系列生成函数

函数描述
generate_series ( start integer, stop integer [, step integer ] ) → setof integer``generate_series ( start bigint, stop bigint [, step bigint ] ) → setof bigint``generate_series ( start numeric, stop numeric [, step numeric ] ) → setof numericstartstop 生成一系列的值,步长为 stepstep 默认为 1。
generate_series ( start timestamp, stop timestamp, step interval ) → setof timestamp``generate_series ( start timestamp with time zone, stop timestamp with time zone, step interval ) → setof timestamp with time zonestartstop 生成一系列的值,步长为 step

step 为正时,如果 start 大于 stop 则返回零行。 相反,当 step 为负时,如果 start 小于 stop 则返回零行。 如果任何输入为 NULL 也会返回零行。step 为零是一个错误。下面是一些例子:

SELECT * FROM generate_series(2,4);
 generate_series
-----------------
               2
               3
               4
(3 rows)

SELECT * FROM generate_series(5,1,-2);
 generate_series
-----------------
               5
               3
               1
(3 rows)

SELECT * FROM generate_series(4,3);
 generate_series
-----------------
(0 rows)

SELECT generate_series(1.1, 4, 1.3);
 generate_series
-----------------
             1.1
             2.4
             3.7
(3 rows)

-- this example relies on the date-plus-integer operator:
SELECT current_date + s.a AS dates FROM generate_series(0,14,7) AS s(a);
   dates
------------
 2004-02-05
 2004-02-12
 2004-02-19
(3 rows)

SELECT * FROM generate_series('2008-03-01 00:00'::timestamp,
                              '2008-03-04 12:00', '10 hours');
   generate_series
---------------------
 2008-03-01 00:00:00
 2008-03-01 10:00:00
 2008-03-01 20:00:00
 2008-03-02 06:00:00
 2008-03-02 16:00:00
 2008-03-03 02:00:00
 2008-03-03 12:00:00
 2008-03-03 22:00:00
 2008-03-04 08:00:00
(9 rows)

下标生成函数

函数描述
generate_subscripts ( array anyarray, dim integer ) → setof integer 生成一个包含给定数组第 dim 维度的有效下标的序列。
generate_subscripts ( array anyarray, dim integer, reverse boolean ) → setof integer 生成一个包含给定数组第 dim 维度的有效下标的序列。当 reverse 为真时,以相反的顺序返回序列。

generate_subscripts 是一个快捷函数,它为给定数组的指定维度生成一组合法的下标。 对于不具有请求维度的数组返回零行,对于任何输入为 NULL 数组也返回零行。下面是一些例子:

-- basic usage:
SELECT generate_subscripts('{NULL,1,NULL,2}'::int[], 1) AS s;
 s
---
 1
 2
 3
 4
(4 rows)

-- presenting an array, the subscript and the subscripted
-- value requires a subquery:
SELECT * FROM arrays;
         a
--------------------
 {-1,-2}
 {100,200,300}
(2 rows)

SELECT a AS array, s AS subscript, a[s] AS value
FROM (SELECT generate_subscripts(a, 1) AS s, a FROM arrays) foo;
     array     | subscript | value
---------------+-----------+-------
 {-1,-2}       |         1 |    -1
 {-1,-2}       |         2 |    -2
 {100,200,300} |         1 |   100
 {100,200,300} |         2 |   200
 {100,200,300} |         3 |   300
(5 rows)

-- unnest a 2D array:
CREATE OR REPLACE FUNCTION unnest2(anyarray)
RETURNS SETOF anyelement AS $$
SELECT $1[i][j]
   FROM generate_subscripts($1,1) g1(i),
        generate_subscripts($1,2) g2(j);
$$ LANGUAGE sql IMMUTABLE;
CREATE FUNCTION
SELECT * FROM unnest2(ARRAY[[1,2],[3,4]]);
 unnest2
---------
       1
       2
       3
       4
(4 rows)

FROM 子句中的函数以 WITH ORDINALITY 作为后缀时,将在函数的输出列上附加一个 bigint 列,该列从 1 开始,函数输出的每一行加 1。 这在 unnest() 等集合返回函数的情况下最有用。

-- set returning function WITH ORDINALITY:
SELECT * FROM pg_ls_dir('.') WITH ORDINALITY AS t(ls,n);
       ls        | n
-----------------+----
 pg_serial       |  1
 pg_twophase     |  2
 postmaster.opts |  3
 pg_notify       |  4
 postgresql.conf |  5
 pg_tblspc       |  6
 logfile         |  7
 base            |  8
 postmaster.pid  |  9
 pg_ident.conf   | 10
 global          | 11
 pg_xact         | 12
 pg_snapshots    | 13
 pg_multixact    | 14
 PG_VERSION      | 15
 pg_wal          | 16
 pg_hba.conf     | 17
 pg_stat_tmp     | 18
 pg_subtrans     | 19
(19 rows)

系统信息函数和运算符

下表展示了多个可以抽取会话和系统信息的函数。

除了本节列出的函数,还有一些与统计系统相关的函数也提供系统信息。

会话信息函数

函数描述
current_catalogname``current_database () → name 返回当前数据库的名称。(在 SQL 标准中数据库被称为“catalogs”,因此current_catalog是该标准的拼写方式。)
current_query () → text 返回当前所执行查询的文本,由客户端提交的(可能包含一个以上的语句)。
current_rolename 这个等同于 current_user
current_schemaname``current_schema () → name 返回在搜索路径中的第一个模式的名称(如果搜索路径为空则返回空值)。 这个模式将用于没有指定目标模式就创建的任何表或其他已命名对象。
current_schemas ( include_implicit boolean ) → name[] 返回当前在有效搜索路径中的所有模式的名称的数组,以优先级顺序。(当前 search_path 设置中与已存在的、可搜索模式不相符的项将被省略。)如果布尔参数为 true,则类似 pg_catalog 的隐式搜索的系统模式将包含在结果中。
current_username 返回当前执行上下文的用户名。
inet_client_addr () → inet 返回当前客户端的 IP 地址,如果当前连接是通过 Unix- 域套接字则返回 NULL
inet_client_port () → integer 返回当前客户端的 IP 端口号,如果当前连接是通过 Unix- 域套接字则返回 NULL
inet_server_addr () → inet 返回服务器接受当前连接的 IP 地址,如果当前连接是通过 Unix- 域套接字则返回 NULL
inet_server_port () → integer 返回服务器接受当前连接的 IP 端口号,如果当前连接是通过 Unix- 域套接字则返回 NULL
pg_backend_pid () → integer 返回附加到当前会话的服务器进程的进程 ID。
pg_blocking_pids ( integer ) → integer[] 返回阻止服务器进程的会话的进程 ID 数组,该进程 ID 与指定的进程 ID 一起获取锁定,如果没有这样的服务器进程或者没有被阻塞,则返回一个空数组。如果一个服务器进程持有一个与被阻塞进程的锁请求冲突的锁(硬阻塞),或者正在等待一个与被阻塞进程的锁请求冲突并且在等待队列中位于其前面的锁(软阻塞),那么这个服务器进程就会阻塞另一个服务器进程。 当使用并行查询时结果总是列出客户端可见的进程 ID(即 pg_backend_pid 的结果),即使实际的锁是由子工作进程持有或等待的。 因此,结果中可能存在重复的 pid。还要注意当准备好的事务持有冲突锁时,它将用零进程 ID 表示。频繁调用这个函数可能会对数据库性能产生一些影响,因为它需要在短时间内独占访问锁管理器的共享状态。
pg_conf_load_time () → timestamp with time zone 返回服务器配置文件最后加载的时间。如果当前会话当时是活跃的,那么这将是会话本身重新读取配置文件的时间(因此在不同的会话中读取会稍有不同)。 否则,就是 postmaster 进程重新读取配置文件的时间。
pg_current_logfile ( [ text ] ) → text 返回日志采集器当前使用的日志文件的路径名。该路径包括 log_directory 目录和单个日志文件名。 如果日志采集器被禁用,结果为 NULL。当存在多个日志文件时,每个文件的格式都不同,不带参数的 pg_current_logfile 将返回在有序列表中找到的第一种格式的文件路径:stderrcsvlog。 如果没有日志文件具有任何这些格式,则返回 NULL。 要请求关于特定日志文件格式的信息,可以提供 csvlogstderr 作为可选参数的值。 如果在 log_destination 中没有配置需要的日志格式,则结果为 NULL。 结果反映了 current_logfiles 文件的内容。
pg_my_temp_schema () → oid 返回当前会话的临时模式的 OID,如果没有则返回 0(因为它没有创建任何临时表)。
pg_is_other_temp_schema ( oid ) → boolean 如果给定的 OID 是另一个会话的临时模式的 OID 则返回真。(这可能是有用的,例如,在目录显示中排除其他会话的临时表。)
pg_jit_available () → boolean 如果 JIT 编译器扩展可用,并且 jit 配置参数设置为 on,则返回真。
pg_listening_channels () → setof text 返回当前会话正在侦听的异步通知通道的名称集。
pg_notification_queue_usage () → double precision 返回当前被等待处理的通知所占用的异步通知队列最大尺寸的分数(0–1)。
pg_postmaster_start_time () → timestamp with time zone 返回服务器启动时的时间。
pg_safe_snapshot_blocking_pids ( integer ) → integer[] 返回一个进程 ID 数组,该进程 ID 是阻塞服务器进程获取安全快照的会话的进程 ID 数组,如果没有这样的服务器进程或者没有阻塞,则返回一个空数组。运行 SERIALIZABLE 事务的会话会阻止 SERIALIZABLE READ ONLY DEFERRABLE 事务获取快照,直到后者确定可以安全地避免获取谓词锁。频繁调用这个函数可能会对数据库性能产生一些影响,因为它需要在短时间内访问谓词锁管理器的共享状态。
pg_trigger_depth () → integer 返回当前嵌套层次的 AntDB 触发器(如果没有调用则为 0,直接或间接,从一个触发器内部开始)。
session_username 返回会话用户名.
username 这个相当于 current_user
version () → text 返回描述 AntDB 服务器的版本的字符串。 还可以从 server_version中 获得此信息,或者对于机器可读的版本,使用 server_version_num。 软件开发人员可以使用 server_version_numPQserverVersion,而不是解析文本版本。

注意

current_catalogcurrent_rolecurrent_schemacurrent_usersession_useruser 在 SQL 里有特殊的语意状态: 它们被调用时结尾不要跟着园括号。 在 AntDB 中,圆括号可以有选择性地被用于 current_schema,但是不能和其他的一起用。

session_user 通常是发起当前数据库连接的用户,不过超级用户可以用 SET SESSION AUTHORIZATION 修改这个设置。 current_user 是用于权限检查的用户标识。通常,它总是等于会话用户,但是可以被 SET ROLE 改变。 它也会在函数执行的过程中随着属性 SECURITY DEFINER 的改变而改变。 在 Unix 的说法里,那么会话用户是“真实用户”,而当前用户是“有效用户”。 current_role以及 usercurrent_user 的同义词(SQL 标准在 current_rolecurrent_user 之间做了区分,但 AntDB 不区分,因为它把用户和角色统一成了一种实体)。

下表列出那些允许编程查询对象访问权限的函数。 在这些函数中,可以通过名称或 OID (pg_authid.oid)指定被查询权限的用户,或者如果名称被指定为 public,则检查 PUBLIC 伪角色的权限。 同样,user 参数可以完全省略,在这种情况下,假设为 current_user。被查询的对象也可以通过名称或 OID 来指定。 通过名称指定时,可以包含相关的模式名称。感兴趣的访问权限由一个文本字符串指定,它必须计算为对象类型的一个适当的权限关键字(例如,SELECT)。 还可以将 WITH GRANT OPTION 添加到权限类型中,以测试该权限是否由授予选项持有。 同样,可以用逗号分隔列出多个权限类型,在这种情况下,如果所列出的权限中有任何一个被持有,结果将为真。(权限字符串的大小写不重要,权限名之间允许有额外的空格,但在权限名中不允许。)一些例子:

SELECT has_table_privilege('myschema.mytable', 'select');
SELECT has_table_privilege('joe', 'mytable', 'INSERT, SELECT WITH GRANT OPTION');

访问权限查询函数

函数描述
has_any_column_privilege ( [ user name or oid, ] table text or oid, privilege text ) → boolean 用户是否对表的任何列有权限? 如果对整个表持有权限,或者对至少一个列有列级的权限授予,则会成功。 允许的权限类型为 SELECTINSERTUPDATEREFERENCES
has_column_privilege ( [ user name or oid, ] table text or oid, column text or smallint, privilege text ) → boolean 用户对指定的表列有权限么?如果对整个表持有权限,或者对列授予了列级别的权限,则会成功。 可以通过名称或属性编号(pg_attribute.attnum)指定列。 允许的权限类型为 SELECTINSERTUPDATEREFERENCES
has_database_privilege ( [ user name or oid, ] database text or oid, privilege text ) → boolean 用户对数据库有权限吗?允许的权限类型为 CREATECONNECTTEMPORARYTEMP (相当于 TEMPORARY)。
has_foreign_data_wrapper_privilege ( [ user name or oid, ] fdw text or oid, privilege text ) → boolean 用户是否拥有外部数据包装的权限?唯一允许的权限类型是 USAGE
has_function_privilege ( [ user name or oid, ] function text or oid, privilege text ) → boolean 用户对函数有权限吗?唯一允许的权限类型是 EXECUTE。当通过名称而不是 OID 指定函数时,允许的输入与 regprocedure 数据类型相同。一个例子为:SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
has_language_privilege ( [ user name or oid, ] language text or oid, privilege text ) → boolean 用户对语言有权限吗?唯一允许的权限类型是 USAGE
has_schema_privilege ( [ user name or oid, ] schema text or oid, privilege text ) → boolean 用户对模式有权限吗?允许的权限类型是 CREATEUSAGE
has_sequence_privilege ( [ user name or oid, ] sequence text or oid, privilege text ) → boolean 用户是否有顺序权限?允许的权限类型有 USAGESELECTUPDATE
has_server_privilege ( [ user name or oid, ] server text or oid, privilege text ) → boolean 用户是否对外部服务器有权限?唯一允许的权限类型是 USAGE
has_table_privilege ( [ user name or oid, ] table text or oid, privilege text ) → boolean 用户对表有权限吗?允许的权限类型有 SELECTINSERTUPDATEDELETETRUNCATEREFERENCESTRIGGER
has_tablespace_privilege ( [ user name or oid, ] tablespace text or oid, privilege text ) → boolean 用户对表空间有权限吗?唯一允许的权限类型是 CREATE
has_type_privilege ( [ user name or oid, ] type text or oid, privilege text ) → boolean 用户对数据类型有权限吗?唯一允许的权限类型是 USAGE。 当通过名称而不是 OID 指定类型时,允许的输入与 regtype 数据类型相同。
pg_has_role ( [ user name or oid, ] role text or oid, privilege text ) → boolean 用户对角色有权限么?允许的权限类型是 MEMBERUSAGEMEMBER 表示角色中的直接或间接成员关系(即执行 SET ROLE 的权利),而 USAGE 表示不执行 SET ROLE 情况下是否立即可用角色的权限。 此函数不允许特殊情况下将 user 设置为 public,因为 PUBLIC 伪角色永远不能成为真实角色的成员。
row_security_active ( table text or oid ) → boolean 在当前用户和当前环境的上下文之中,指定表的行级安全是活动的吗?

下表显示了 aclitem 类型的可用操作符,它是访问权限的目录表示。 有关如何读取访问权限值的信息。

aclitem 操作符

操作符描述例子
aclitem = aclitemboolean``aclitem 相等吗?(注意,aclitem 类型缺少比较操作符的通常集合;它只有相等。 反而言之,aclitem 数组只能进行相等比较。)'calvin=r*w/hobbes'::aclitem = 'calvin=r*w*/hobbes'::aclitemf
aclitem[] @> aclitemboolean 数组是否包含指定的权限?(如果有一个数组条目与 aclitem 的被授权人和授予人相匹配,并且至少具有权限的指定集,则此选项为真。)'{calvin=r*w/hobbes,hobbes=r*w*/antdb}'::aclitem[] @> 'calvin=r*/hobbes'::aclitemt
aclitem[] ~ aclitemboolean 这是 @> 的已弃用别名。'{calvin=r*w/hobbes,hobbes=r*w*/antdb}'::aclitem[] ~ 'calvin=r*/hobbes'::aclitemt

下表显示了一些额外的函数来管理 aclitem 类型。

aclitem 函数

函数描述
acldefault ( type "char", ownerId oid ) → aclitem[] 构造一个 aclitem 数组,该数组持有 type 类型对象的默认访问权限,该对象属于 OID 为 ownerId 的角色。 这表示当对象的 ACL 条目为空时所假定的访问权限。 type 参数必须是下列中的一个 'c' 对应 COLUMN,'r' 对应 TABLE 和类表对象, 's' 对应 SEQUENCE, 'd' 对应 DATABASE,'f' 对应 FUNCTIONPROCEDURE, 'l' 对应 LANGUAGE, 'L' 对应 LARGE OBJECT,'n' 对应 SCHEMA,'t' 对应 TABLESPACE, 'F' 对应 FOREIGN DATA WRAPPER, 'S' 对应 FOREIGN SERVER或 'T' 对应 TYPEDOMAIN.
aclexplode ( aclitem[] ) → setof record ( grantor oid, grantee oid, privilege_type text, is_grantable boolean ) 以行集的形式返回 aclitem 数组。如果受让人是伪角色 PUBLIC,则在 grantee 列中用 0 表示。 每个被授予的权限都表示为 SELECTINSERT等。 注意,每个权限被分割成单独的一行,因此在 privilege_type 列中只出现一个关键字。
makeaclitem ( grantee oid, grantor oid, privileges text, is_grantable boolean ) → aclitem 使用给定的属性构造 aclitem

下表展示了决定是否一个特定对象在当前模式搜索路径中可见的函数。 例如,如果一个表所在的模式在当前搜索路径中并且在它之前没有出现过相同的名字,这个表就被说是可见的。 这等价于在语句中表可以被用名称引用但不加显式的模式限定。因此,要列出所有可见表的名字:

SELECT relname FROM pg_class WHERE pg_table_is_visible(oid);

对于函数和操作符,如果路径前面没有相同名称 and argument data type(s) 的对象,那么搜索路径中的对象就是可见的。 对于操作符类和操作符族,要考虑名称和关联的索引访问方法。

模式可见性查询函数

函数描述
pg_collation_is_visible ( collation oid ) → boolean 排序规则在搜索路径中可见吗?
pg_conversion_is_visible ( conversion oid ) → boolean 转换在搜索路径中可见吗?
pg_function_is_visible ( function oid ) → boolean 函数在搜索路径中可见吗?(这也适用于过程和聚合。)
pg_opclass_is_visible ( opclass oid ) → boolean 操作符类在搜索路径中可见吗?
pg_operator_is_visible ( operator oid ) → boolean 操作符在搜索路径中可见吗?
pg_opfamily_is_visible ( opclass oid ) → boolean 操作符族在搜索路径中可见吗?
pg_statistics_obj_is_visible ( stat oid ) → boolean 统计对象在搜索路径中可见吗?
pg_table_is_visible ( table oid ) → boolean 表在搜索路径中可见吗?(这适用于所有类型的关系,包括视图、物化视图、索引、序列和外部表。)
pg_ts_config_is_visible ( config oid ) → boolean 文本搜索配置在搜索路径可见吗?
pg_ts_dict_is_visible ( dict oid ) → boolean 文本搜索字典在搜索路径可见吗?
pg_ts_parser_is_visible ( parser oid ) → boolean 文本搜索解析器在搜索路径中可见吗?
pg_ts_template_is_visible ( template oid ) → boolean 文本搜索模板在搜索路径可见吗?
pg_type_is_visible ( type oid ) → boolean 类型(或域)在搜索路径中可见吗?

所有这些函数都要求用对象 OID 来标识将被检查的对象。如果想用名称来测试一个对象,使用 OID 别名类型(regclassregtyperegprocedureregoperatorregconfigregdictionary)将会很方便。例如:

SELECT pg_type_is_visible('myschema.widget'::regtype);

注意以这种方式测试一个非模式限定的类型名没什么意义 — 如果该名称完全能被识别,它必须是可见的。

下表列出从系统目录中提取信息的函数。

系统目录信息函数

函数描述
format_type ( type oid, typemod integer ) → text 返回由其类型 OID 和可能的类型修饰符标识的数据类型的 SQL 名称。如果没有已知的类型修饰符,则传递 NULL 值给类型修饰符。
pg_get_constraintdef ( constraint oid [, pretty boolean ] ) → text 重构为了约束的创建命令。(这是一个反编译的重构,而不是命令的原始文本。)
pg_get_expr ( expr pg_node_tree, relation oid [, pretty boolean ] ) → text 反编译存储在系统目录中的表达式的内部形式,例如列的默认值。 如果表达式可能包含变量,则指定它们所指向的关系的 OID 作为第二个参数;如果没有预期的变量,传递 0 就可以了。
pg_get_functiondef ( func oid ) → text 重构为了函数或过程的创建命令。(这是一个反编译的重构,而不是命令的原始文本。)结果是一个完整的 CREATE OR REPLACE FUNCTIONCREATE OR REPLACE PROCEDURE 语句。
pg_get_function_arguments ( func oid ) → text 重新构造函数或过程的参数列表,以其在 CREATE FUNCTION 里面需要出现的形式(包括默认值)。
pg_get_function_identity_arguments ( func oid ) → text 重新构造标识函数或过程所需的参数列表,以其应出现在 ALTER FUNCTION 等命令中的形式。这个表单省略默认值。
pg_get_function_result ( func oid ) → text 重构函数的 RETURNS 子句,以其需要出现在 CREATE FUNCTION 中的形式。对于过程,返回 NULL
pg_get_indexdef ( index oid [, column integer, pretty boolean ] ) → text 重构针对索引的创建命令。(这是一个反编译的重构,而不是命令的原始文本。)如果提供了 column 而且不为零,则只重构该列的定义。
pg_get_keywords () → setof record ( word text, catcode "char", catdesc text ) 返回一组描述服务器识别的 SQL 关键字的记录。word 列包含关键字。 catcode 列包含一个类别代码:U 表示无保留关键字,C 表示可以是列名的关键字,T 表示可以是类型或函数名的关键字,或者 R 表示完全保留关键字。 catdesc 列包含描述类别的可能本地化字符串。
pg_get_ruledef ( rule oid [, pretty boolean ] ) → text 重构针对规则的创建命令。(这是一个反编译的重构,而不是命令的原始文本。)
pg_get_serial_sequence ( table text, column text ) → text 返回与列相关联的序列名称,如果没有序列与该列相关联则返回 NULL。 如果列是标识列,则关联序列是在内部为该列创建的序列。 对于使用一种串行类型(serialsmallserialbigserial)创建的列,它是为该串行列定义创建的序列。 在后一种情况下,可以使用 ALTER SEQUENCE OWNED BY 修改或删除关联。(这个函数可能应该被称为 pg_get_owned_sequence;它的当前名称反映了它在历史上曾与串行类型的列一起使用。)第一个参数是具有可选模式的表名,第二个参数是列名。 由于第一个参数可能包含模式名和表名,因此按照通常的 SQL 规则解析它,这意味着默认情况下它是小写的。 第二个参数只是一个列名,按照字面来处理,因此保留了它的大小写。结果经过了适当的格式化,可以传递给序列函数。典型的用法是读取序列的当前值以获取标识或串行列,示例如下:SELECT currval(pg_get_serial_sequence('sometable', 'id'));
pg_get_statisticsobjdef ( statobj oid ) → text 重构针对扩展统计对象的创建命令。(这是一个反编译的重构,而不是命令的原始文本。)
pg_get_triggerdef ( trigger oid [, pretty boolean ] ) → text 重构针对触发器的创建命令。(这是一个反编译的重构,而不是命令的原始文本。)
pg_get_userbyid ( role oid ) → name 根据 OID 返回角色名。
pg_get_viewdef ( view oid [, pretty boolean ] ) → text 重构针对视图或物化视图的 SELECT 命令。(这是一个反编译的重构,而不是命令的原始文本。)
pg_get_viewdef ( view oid, wrap_column integer ) → text 重构针对视图或物化视图的底层 SELECT 命令。(这是一个反编译的重构,而不是命令的原始文本。)在这种形式的函数中,总是启用美观打印,并对长行进行换行,以尽量使它们小于指定的列数。
pg_get_viewdef ( view text [, pretty boolean ] ) → text 根据视图的文本名称而不是它的 OID,重构针对视图或物化视图的底层 SELECT 命令。(这是弃用;请使用 OID 变体。)
pg_index_column_has_property ( index regclass, column integer, property text ) → boolean 测试一个索引列是否具有命名属性。(注意,扩展访问方法可以为其索引定义额外的属性名。) 如果属性名未知或不适用于特定对象,或者 OID 或列号不能识别有效的对象,则返回 NULL
pg_index_has_property ( index regclass, property text ) → boolean 测试一个索引是否具有命名属性。 (注意,扩展访问方法可以为其索引定义额外的属性名。) 如果属性名未知或不适用于特定对象,或者 OID 不能识别有效的对象,则返回 NULL
pg_indexam_has_property ( am oid, property text ) → boolean 测试索引访问方法是否具有命名属性。 如果属性名未知或不适用于特定对象,或者 OID 不能识别有效的对象,则返回 NULL
pg_options_to_table ( options_array text[] ) → setof record ( option_name text, option_value text ) 返回源自pg_class.reloptionspg_attribute.attoptions 的值表示的存储选项集。
pg_tablespace_databases ( tablespace oid ) → setof oid 返回具有存储在指定表空间中的对象的数据库的 OIDs 集。 如果这个函数返回了任何行,那么表空间就不是空的,且不能被删除。 要识别填充表空间的特定对象,需要连接到由 pg_tablespace_databases 标识的数据库,并查询它们的 pg_class 目录。
pg_tablespace_location ( tablespace oid ) → text 返回表空间所在的文件系统路径。
pg_typeof ( "any" ) → regtype 返回传递值给它的数据类型的 OID。这对于故障排除或动态构造 SQL 查询很有帮助。 函数声明为返回 regtype,它是一个 OID 别名类型;这意味着,为了比较,它与 OID 相同,但显示为类型名。例如:SELECT pg_typeof(33); pg_typeof ----------- integer SELECT typlen FROM pg_type WHERE oid = pg_typeof(33); typlen -------- 4
COLLATION FOR ( "any" ) → text 返回传递值给它的排序规则的名称。如果需要,该值会被引号括起来,并使用模式限定。 如果没有为参数表达式派生排序规则,则返回 NULL。如果参数不是可排序数据类型,则会引发错误。例如:SELECT collation for (description) FROM pg_description LIMIT 1; pg_collation_for ------------------ "default" SELECT collation for ('foo' COLLATE "de_DE"); pg_collation_for ------------------ "de_DE"
to_regclass ( text ) → regclass 将文本关系名转换为它的 OID。通过将字符串类型转换为 regclass 可以得到类似的结果;但是,如果没有找到名称,这个函数将返回 NULL 而不会抛出错误。与强制转换不同的是,它不接受数字 OID 作为输入。
to_regcollation ( text ) → regcollation 将文本排序规则名称转换为它的 OID。通过将字符串类型转换为 regcollation 可以得到类似的结果;但是,如果没有找到名称,这个函数将返回 NULL 而不会抛出错误。与强制转换不同的是,它不接受数字 OID 作为输入。
to_regnamespace ( text ) → regnamespace 将文本模式名转换为它的 OID。通过将字符串转换为 regnamespace 类型可以得到类似的结果;但是,如果没有找到名称,这个函数将返回 NULL 而不会抛出错误。与强制转换不同的是,它不接受数字 OID 作为输入。
to_regoper ( text ) → regoper 将文本操作符名称转换为它的 OID。通过将字符串类型转换为 regoper 可以得到类似的结果; 但是,如果找不到名称或名称有多义性,该函数将返回 NULL 而不会抛出错误。与强制转换不同的是,它不接受数字 OID 作为输入。
to_regoperator ( text ) → regoperator 将文本操作符名称(带有参数类型)转换为其 OID。通过将字符串转换为regoperator类型节可以得到类似的结果;但是,如果没有找到名称,这个函数将返回 NULL 而不会抛出错误。与强制转换不同的是,它不接受数字 OID 作为输入。
to_regproc ( text ) → regproc 将文本函数或过程名转换为其 OID。通过将字符串转换为 regproc 类型可以得到类似的结果;但是,如果找不到名称或名称有多义性,该函数将返回 NULL 而不会抛出错误。与强制转换不同的是,它不接受数字 OID 作为输入。
to_regprocedure ( text ) → regprocedure 将文本函数或过程名(带有参数类型)转换为其 OID。通过将字符串类型转换为 regprocedure 可以得到类似的结果; 但是,如果没有找到名称,这个函数将返回 NULL 而不会抛出错误。与强制转换不同的是,它不接受数字 OID 作为输入。
to_regrole ( text ) → regrole 将文本角色名转换为它的 OID。通过将字符串类型转换为 regrole 可以得到类似的结果;但是,如果没有找到名称,这个函数将返回 NULL 而不会抛出错误。与强制转换不同的是,它不接受数字 OID 作为输入。
to_regtype ( text ) → regtype 将文本类型名转换为它的 OID。通过将字符串类型转换为 regtype 可以得到类似的结果;但是,如果没有找到名称,这个函数将返回 NULL 而不会抛出错误。与强制转换不同的是,它不接受数字 OID 作为输入。

大多数重构(反编译)数据库对象的函数都有一个可选的 pretty 标志,如果为 true,结果将被“pretty-printed”。 美观打印会抑制不必要的圆括号,并为易读性增加空格。 美观打印的格式可读性更好,但是默认格式更有可能被AntDB的未来版本以同样的方式解释; 因此,避免为转储目的使用美观打印的输出。为 pretty 参数传递 false 会产生与省略参数相同的结果。

索引列属性

名称描述
asc在向前扫描时列是按照升序排列吗?
desc在向前扫描时列是按照降序排列吗?
nulls_first在向前扫描时列排序会把空值排在前面吗?
nulls_last在向前扫描时列排序会把空值排在最后吗?
orderable列具有已定义的排序顺序吗?
distance_orderable列能否通过一个“distance”操作符(例如ORDER BY col <-> constant)有序地扫描?
returnable列值是否可以通过一次只用索引扫描返回?
search_array列是否天然支持col = ANY(array)搜索?
search_nulls列是否支持 IS NULLIS NOT NULL 搜索?

索引性质

名称描述
clusterable索引是否可以用于 CLUSTER 命令?
index_scan索引是否支持普通扫描(非位图)?
bitmap_scan索引是否支持位图扫描?
backward_scan在扫描中扫描方向能否被更改(为了支持游标上无需物化的 FETCH BACKWARD)?

索引访问方法性质

名称描述
can_order访问方法是否支持 ASCDESC 以及 CREATE INDEX 中的有关关键词?
can_unique访问方法是否支持唯一索引?
can_multi_col访问方法是否支持多列索引?
can_exclude访问方法是否支持排除约束?
can_include访问方法是否支持 CREATE INDEXINCLUDE 子句?

下表列出了与数据库对象 标识和定位有关的函数。

对象信息和定位函数

函数描述
pg_describe_object ( classid oid, objid oid, objsubid integer ) → text 返回由目录 OID、对象 OID 和子对象 ID(例如表中的列号)标识的数据库对象的文本描述;当引用整个对象时,子对象 ID 为 0。 这个描述是人类可读的,并且可以根据服务器配置进行翻译。这对于决定 pg_depend 目录中引用的对象的标识特别有用。
pg_identify_object ( classid oid, objid oid, objsubid integer ) → record ( type text, schema text, name text, identity text ) 返回包含足够信息的行以唯一标识由目录 OID、对象 OID 和子对象 ID 指定的数据库对象。 这些信息是为了机器可读的,永远不会被翻译。 type 标识数据库对象的类型;schema 是对象所属的模式名,NULL 表示不属于模式的对象类型;name 是对象的名称,如果有必要,用引号括起来,如果名称(随着模式名称,如果相关)足以唯一地标识对象,否则为 NULLidentity 是完整的对象标识,其精确格式依赖于对象类型,格式中的每个名称都是模式限定的,并在必要时用引号括起来。
pg_identify_object_as_address ( classid oid, objid oid, objsubid integer ) → record ( type text, object_names text[], object_args text[] ) 返回包含足够信息的行以唯一标识由目录 OID、对象 OID 和子对象 ID 指定的数据库对象。 返回的信息独立于当前服务器,也就是说,它可以用于标识另一个服务器中具有相同名称的对象。 type 标识数据库对象的类型;object_namesobject_args 是文本数组,它们一起构成对对象的引用。 这三个值可以传递给 pg_get_object_address 以获得对象的内部地址。
pg_get_object_address ( type text, object_names text[], object_args text[] ) → record ( classid oid, objid oid, objsubid integer ) 返回包含足够信息的行以唯一标识由类型代码、对象名称和参数数组指定的数据库对象。返回的值将在系统目录中使用,例如 pg_depend;它们可以传递给其他系统函数,比如 pg_describe_objectpg_identify_objectclassid 是包含该对象的系统目录的 OID;objid 是对象本身的 OID, objsubid 是子对象的 ID,如果没有则为零。 这个函数是 pg_identify_object_as_address 的反向函数。

下表中展示的函数抽取注释,注释是由 COMMENT 命令在以前存储的。如果对指定参数找不到注释,则返回空值。

注释信息函数

函数描述
col_description ( table oid, column integer ) → text 返回表列的注释,该注释由该表的 OID 和列号指定。(obj_description 不能用于表的列,因为列没有自己的 oid。)
obj_description ( object oid, catalog name ) → text 返回 OID 指定的数据库对象的注释和包含该对象的系统目录的名称。 例如,obj_description(123456, 'pg_class') 将检索 OID 为 123456 的表的注释。
obj_description ( object oid ) → text 返回仅由其 OID 指定的数据库对象的注释。 这个已被*弃用(deprecated)*因为无法保证 oid 在不同的系统目录中是唯一的;因此,可能会返回错误的注释。
shobj_description ( object oid, catalog name ) → text 返回共享数据库对象的注释,该对象由其 OID 和包含的系统编目的名称指定。 这与 obj_description 类似,只是它用于检索共享对象(也就是数据库、角色和表空间)上的注释。 有些系统编目对每个集群中的所有数据库都是全局的,其中对象的描述也全局存储。

下表中展示的函数以一种可导出的形式提供了服务器事务信息。 这些函数的主要用途是判断在两个快照之间哪些事务被提交。

事务ID和快照信息功能

函数描述
pg_current_xact_id () → xid8 返回当前事务的 ID。如果当前事务还没有一个 ID(因为它还没有执行任何数据库更新),它将分配一个新的事务。
pg_current_xact_id_if_assigned () → xid8 返回当前事务的 ID,如果还没有分配 ID则返回 NULL。 (如果事务可能是只读的,最好使用这种变体,以避免不必要地消耗 XID。)
pg_xact_status ( xid8 ) → text 报告最近的事务的提交状态。如果事务为最近的,系统会保留事务的提交状态,则结果是 in progresscommittedaborted。 如果该事务的时间足够久,并且系统中没有对该事务的引用,而且提交状态信息已经被丢弃,则结果为 NULL。 应用可以使用此函数,例如,确定在进行 COMMIT 时,应用程序和数据库服务器断开连接后,它们的事务是已提交还是中止。 注意,准备好的事务报告为 in progress 的事务;如果应用需要确定一个事务 ID 是否属于一个准备好的事务,则必须检查 pg_prepared_xacts
pg_current_snapshot () → pg_snapshot 返回当前 snapshot,显示哪些事务 IDs 正在进行中的数据结构。
pg_snapshot_xip ( pg_snapshot ) → setof xid8 返回快照中包含的正在进行的事务 IDs 集。
pg_snapshot_xmax ( pg_snapshot ) → xid8 返回快照的 xmax
pg_snapshot_xmin ( pg_snapshot ) → xid8 返回快照的 xmin
pg_visible_in_snapshot ( xid8, pg_snapshot ) → boolean 根据此快照,给定的事务 ID 是否可见(visible)(也就是说,它是否在快照拍摄之前完成)? 注意,这个函数不会给出子事务 ID 的正确答案。

内部事务 ID 类型 xid 是 32 位宽的,可回卷(wraps around)每 40 亿个事务。 但是,上表中所示的函数使用的是 64 位类型的 xid8,它在安装过程中不回卷(wraps around),如果需要,可以通过强制转换将其转换为 xid。 数据类型 pg_snapshot 存储特定时刻事务 ID 可见性的信息。pg_snapshot 的文本表示形式是*xmin*:*xmax*:*xip_list*。 例如 10:20:10,14,15 表示 xmin=10, xmax=20, xip_list=10, 14, 15

快照组件

名称描述
xmin仍然处于活动状态的最低事务 ID。所有小于 xmin 的事务 IDs 要么提交且可见,要么回滚并死亡。
xmax比最高完成的事务 ID 还高出一个值。所有大于或等于 xmax 的事务 IDs 到快照时还没有完成,因此不可见。
xip_list快照时正在进行的事务。一个事务 ID 为 xmin <= *X* < xmax 且不在快照时已经完成的列表中,因此根据其提交状态,该事务 ID 要么是可见的,要么是死的。此列表不包括子事务的事务 IDs。

在 AntDB 以前的版本中,没有 xid8 类型,因此提供了这些函数的变体,使用 bigint 表示 64 位 XID,并相应地提供不同的快照数据类型 txid_snapshot。 这些旧的函数在它们的名字中有 txid。 它们仍然支持向后兼容性,但可能会从未来的版本中删除。

已弃用的事务 ID 和快照信息功能

函数描述
txid_current () → bigint 参见 pg_current_xact_id().
txid_current_if_assigned () → bigint 参见 pg_current_xact_id_if_assigned().
txid_current_snapshot () → txid_snapshot 参见 pg_current_snapshot().
txid_snapshot_xip ( txid_snapshot ) → setof bigint 参见 pg_snapshot_xip().
txid_snapshot_xmax ( txid_snapshot ) → bigint 参见 pg_snapshot_xmax().
txid_snapshot_xmin ( txid_snapshot ) → bigint 参见 pg_snapshot_xmin().
txid_visible_in_snapshot ( bigint, txid_snapshot ) → boolean 参见 pg_visible_in_snapshot().
txid_status ( bigint ) → text 参见 pg_xact_status().

下表中的函数提供了关于过去的事务何时被提交的信息。 它们只在启用 track_commit_timestamp 配置选项时提供有用的数据,并且只针对在启用该选项后提交的事务。

已提交事务信息函数

函数描述
pg_xact_commit_timestamp ( xid ) → timestamp with time zone 返回事务的提交时间戳。
pg_last_committed_xact () → record ( xid xid, timestamp timestamp with time zone ) 返回最近提交的事务的事务 ID 和提交时间戳。

下表中所展示的函数能打印 initdb 期间初始化的信息,例如目录版本。 它们也能显示有关预写式日志和检查点处理的信息。这些信息是集簇范围内的,不与任何特定的一个数据库相关。 这些函数提供大致相同的信息,对于同一种来源,就像 adb_controldata 应用。

控制数据函数

函数描述
pg_control_checkpoint () → record 返回有关当前检查点状态的信息。
pg_control_system () → record 返回有关当前控制文件状态的信息。
pg_control_init () → record 返回有关集群初始化状态的信息。
pg_control_recovery () → record 返回有关恢复状态的信息。

pg_control_checkpoint 输出列

列名称数据类型
checkpoint_lsnpg_lsn
redo_lsnpg_lsn
redo_wal_filetext
timeline_idinteger
prev_timeline_idinteger
full_page_writesboolean
next_xidtext
next_oidoid
next_multixact_idxid
next_multi_offsetxid
oldest_xidxid
oldest_xid_dbidoid
oldest_active_xidxid
oldest_multi_xidxid
oldest_multi_dbidoid
oldest_commit_ts_xidxid
newest_commit_ts_xidxid
checkpoint_time带时区的时间戳

pg_control_system 输出列

列名称数据类型
pg_control_versioninteger
catalog_version_nointeger
system_identifierbigint
pg_control_last_modifiedtimestamp with time zone

pg_control_init 输出列

列名称数据类型
max_data_alignmentinteger
database_block_sizeinteger
blocks_per_segmentinteger
wal_block_sizeinteger
bytes_per_wal_segmentinteger
max_identifier_lengthinteger
max_index_columnsinteger
max_toast_chunk_sizeinteger
large_object_chunk_sizeinteger
float8_pass_by_valueboolean
data_page_checksum_versioninteger

pg_control_recovery 输出列

列名称数据类型
min_recovery_end_lsnpg_lsn
min_recovery_end_timelineinteger
backup_start_lsnpg_lsn
backup_end_lsnpg_lsn
end_of_backup_record_requiredboolean

系统管理函数

配置设定函数

下表展示了那些可以用于查询以及修改运行时配置参数的函数。

配置设置函数

函数描述例子
current_setting ( setting_name text [, missing_ok boolean ] ) → text 返回设置的 setting_name 的当前值。 如果没有这样的设置,current_setting 将抛出一个错误,除非 missing_ok 被提供并且为 true。 这个函数对应于 SQL 命令 SHOWcurrent_setting('datestyle')ISO, MDY
set_config ( setting_name text, new_value text, is_local boolean ) → text 将参数 setting_name 设置为 new_value,并返回该值。 如果 is_localtrue,新值将仅在当前事务中应用。 如果希望新值应用于当前会话的其余部分,请使用 false 代替。这个函数对应于 SQL 命令 SETset_config('log_statement_stats', 'off', false)off

服务器信号函数

在下表中展示的函数向其它服务器进程发送控制信号。默认情况下这些函数只能被超级用户使用,但是如果需要,可以利用 GRANT 把访问权限授予给其他用户。

每个这样的函数如果成功则返回 true,否则返回 false

服务器信号函数

函数描述
pg_cancel_backend ( pid integer ) → boolean 取消对后端进程具有指定进程 ID的会话的当前查询。 如果调用角色是后端被取消的角色的成员,或者调用角色被授予 pg_signal_backend,也允许这样做,但是只有超级用户才能取消超级用户后端。
pg_reload_conf () → boolean 导致 AntDB 服务器的所有进程重新加载其配置文件。(这是通过向 postmaster 进程发送 SIGHUP 信号来初始化的,然后这个进程又把 SIGHUP 发送给它的每个子进程。)
pg_rotate_logfile () → boolean 通知日志文件管理器立即切换到一个新的输出文件。 这仅在内置日志采集器运行时有效,因为否则没有日志文件管理器子进程。
pg_terminate_backend ( pid integer ) → boolean 终止后端进程具有指定进程ID的会话。 如果调用角色是后端被终止的角色的成员,或者调用角色被赋予 pg_signal_backend,那么也允许这样做,但是只有超级用户才能终止超级用户后端。

pg_cancel_backendpg_terminate_backend 向由进程 ID 标识的后端进程发送信号(分别是 SIGINT 或 SIGTERM)。 一个活动后端的进程 ID 可以从 pg_stat_activity 视图的 pid 列中找到,或者通过在服务器上列出 antdb 进程(在 Unix 上使用 ps 或者在 Windows 上使用任务管理器)得到。 一个活动后端的角色可以在 pg_stat_activity 视图的 usename 列中找到。

备份控制函数

下表中展示的函数可以辅助制作在线备份。 这些函数不能在恢复期间执行(非排他性的 pg_start_backup,非排他性的pg_stop_backuppg_is_in_backuppg_backup_start_timepg_wal_lsn_diff 除外)。

备份控制函数

函数描述
pg_create_restore_point ( name text ) → pg_lsn 在预写式日志中创建一个命名标记记录,稍后可以将其用作恢复目标,并返回相应的预写日志位置。 然后可以将给定的名称与 recovery_target_name 一起使用,以指定进行恢复的点。 要避免创建多个名称相同的恢复点,因为恢复将在第一个名称与恢复目标匹配的恢复点停止。默认情况下,该函数仅限超级用户使用,但可以授权给其他用户执行该函数。
pg_current_wal_flush_lsn () → pg_lsn 返回当前预写式日志刷新位置(参见下面的说明)。
pg_current_wal_insert_lsn () → pg_lsn 返回当前预式日志插入位置(参见下面的说明)。
pg_current_wal_lsn () → pg_lsn 返回当前预写式日志写位置(参见下面的说明)。
pg_start_backup ( label text [, fast boolean [, exclusive boolean ]] ) → pg_lsn 准备服务器开始在线备份。唯一需要的参数是用于备份的任意用户定义的标签。(通常,备份转储文件将存储在这个名称下。)如果可选的第二个参数被指定为 true,它将指定尽可能快地执行 pg_start_backup。 这将强制产生一个即时检查点,这将导致 I/O 操作突增,从而降低并发执行的查询的速度。 第三个可选参数指定是执行排他或非排他备份(默认为排他备份)。在排他模式下使用时,该函数将写一个备份标签文件(backup_label),如果 pg_tblspc/ 目录中有任何链接, 则将一个表空间映射文件(tablespace_map)写入数据库集群的数据目录,然后执行检查点,然后返回备份的开始写-提前日志位置。(用户可以忽略这个结果值,但在有用的情况下会提供它。) 在非排他模式下使用时,这些文件的内容将由 pg_stop_backup 函数返回,并且应该由用户复制到备份区域。默认情况下,该函数仅限超级用户使用,但可以授权其他用户 EXECUTE 该函数。
pg_stop_backup ( exclusive boolean [, wait_for_archive boolean ] ) → setof record ( lsn pg_lsn, labelfile text, spcmapfile text ) 完成排他或非排他联机备份。exclusive 参数必须与前面的 pg_start_backup 调用相匹配。 在排他备份中, pg_stop_backup 删除备份标签文件,如果存在,则删除 pg_start_backup 创建的表空间映射文件。 在非排他备份中,这些文件的所需内容将作为函数结果的一部分返回,并且应该写入备份区域(不在数据目录)中的文件。还有一个可选的 boolean 类型的第二个参数。如果为假,则该函数将在备份完成后立即返回,而无需等待 WAL 被归档。 这种行为只有在独立监控 WAL 归档的备份软件中才有用。否则,使备份一致所需的 WAL 可能会丢失,从而使备份无效。 默认情况下或当该参数为真时,pg_stop_backup 将在启用归档时等待 WAL 被归档。(在备用状态下,这意味着只有当 archive_mode = always 时,它才会等待。 如果主节点上的写活动很少,那么可以在主节点上运行 pg_switch_wal 来触发立即段切换。)当在主节点上执行时,这个函数还会在预写式日志归档区域中创建一个备份历史文件。 历史文件包括给予 pg_start_backup 的标签,备份的开始和结束写前预写式日志的位置,以及备份的开始和结束时间。 记录完结束位置后,当前的预写式日志插入点自动移到下一个预写式日志文件,以便结束的预写式日志文件可以立即归档,从而完成备份。该函数的结果是一条记录。lsn 列保持备份的结束预写式日志位置(可以再忽略)。 当结束排他备份时,第二和第三列为 NULL;在非排他备份之后,它们保持标签和表空间映射文件所需的内容。默认情况下该函数仅限超级用户使用,但也可以授权其他用户执行该函数。
pg_stop_backup () → pg_lsn 结束执行排他在线备份。这个简化版本等同于 pg_stop_backup(true, true),只是它只返回 pg_lsn 结果。默认情况下该函数仅限超级用户使用,但可以授权其他用户执行该函数。
pg_is_in_backup () → boolean 如果正在进行联机排他备份则返回真。
pg_backup_start_time () → timestamp with time zone 如果正在进行在线排他备份,则返回当前在线排他备份的开始时间,否则为 NULL
pg_switch_wal () → pg_lsn 强制服务器切换到一个新的预写式日志文件,这允许对当前文件进行归档(假设正在使用连续归档)。 其结果是在刚刚完成的预写式日志文件中结束预写式日志位置加 1。 如果自从上次预写式日志切换以来没有提前写日志活动,pg_switch_wal 将不做任何操作,并返回当前正在使用的提前写日志文件的起始位置。默认情况下该函数仅限超级用户使用,但可以授权其他用户执行该函数。
pg_walfile_name ( lsn pg_lsn ) → text 将预写式日志位置转换为保持该位置的 WAL 文件的名称。
pg_walfile_name_offset ( lsn pg_lsn ) → record ( file_name text, file_offset integer ) 将预写式日志位置转换为 WAL 文件名和该文件中的字节偏移量。
pg_wal_lsn_diff ( lsn pg_lsn, lsn pg_lsn ) → numeric 计算两个预写式日志位置之间的字节差。 这可以与 pg_stat_replication 一起使用,以获得复制延迟。

pg_current_wal_lsn 显示当前预写式日志写位置,与上述函数所用的格式相同。 类似地,pg_current_wal_insert_lsn 显示当前预写式日志插入位置,pg_current_wal_flush_lsn 显示当前预写式日志刷新位置。 插入位置是预写式日志在任何时刻的“逻辑(logical)” 结束,而写位置是已经从服务器内部缓冲区实际写入的内容的结束,而刷新位置是已知的要写入持久化存储的最后一个位置。 写位置是可以从服务器外部检查的最后位置,如果对归档部分完成的预写式日志文件感兴趣,那么它通常就是想要的位置。 插入和刷新位置主要用于服务器调试目的。这些都是只读操作,不需要超级用户权限。

可以使用 pg_walfile_name_offsetpg_lsn 值中提取相应的预写式日志文件名称和字节偏移量。例如:

antdb=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
        file_name         | file_offset
--------------------------+-------------
 00000001000000000000000D |     4039624
(1 row)

类似地,pg_walfile_name 只提取预写式日志文件名称。 当给定的预写式日志位置恰好位于预写式日志文件的边界时,这两个函数都会返回前一个预写式日志文件的名称。 这通常是管理预写式日志归档行为所需的行为,因为前面的文件是当前需要归档的最后一个文件。

恢复控制函数

下表中展示的函数提供有关后备服务器当前状态的信息。 这些函数可以在恢复或普通运行过程中被执行。

恢复信息函数

函数描述
pg_is_in_recovery () → boolean 如果恢复仍在进行则返回真。
pg_last_wal_receive_lsn () → pg_lsn 返回已接收并通过流复制同步到磁盘的最后一个预写式日志位置。 当流复制正在进行时这将单调地增加。如果恢复已经完成,那么在恢复期间,接收到的最后一条 WAL 记录的位置将保持静态,并同步到磁盘。 如果流复制已禁用,或者尚未启动,函数将返回 NULL
pg_last_wal_replay_lsn () → pg_lsn 返回恢复期间重新播放的最后一个预写式日志位置。如果恢复仍在进行中这将会单调地增加。 如果恢复已经完成,那么恢复期间应用的最后 WAL 记录的位置将保持静态。当服务器正常启动且没有恢复时,函数返回 NULL
pg_last_xact_replay_timestamp () → timestamp with time zone 返回恢复期间重放的最后一个事务的时间戳。这是在主服务器上为该事务生成提交或中止 WAL 记录的时间。 如果在恢复期间没有重放任何事务,该函数将返回 NULL。否则,如果恢复仍在进行中,这将单调地增加。 如果恢复已经完成,那么在恢复期间应用最后一个事务时,这将会保持静态。 当服务器正常启动且没有恢复时,函数返回 NULL

控制恢复进度的功能如下表所示。这些函数只能在恢复过程中执行。

恢复控制函数

函数描述
pg_is_wal_replay_paused () → boolean 如果恢复暂停了则返回真。
pg_promote ( wait boolean DEFAULT true, wait_seconds integer DEFAULT 60 ) → boolean 将备用服务器提升为主服务器状态。 当 wait 设置为 true(默认值)时,函数将等待直到升级完成或 wait_seconds 秒数已过,如果升级成功则返回 true,否则返回 false。 如果 wait 设置为 false,则该函数在向 postmaster 发送 SIGUSR1 信号以触发升级后立即返回 true。默认情况下这个函数仅限超级用户使用,但可以授权给其他用户执行该函数。
pg_wal_replay_pause () → void 暂停恢复。在恢复暂停时,不会应用进一步的数据库更改。 如果热备是激活的,所有新查询将看到相同的一致的数据库快照,并且在恢复继续之前不会生成进一步的查询冲突。默认情况下该函数仅限超级用户使用,但可以授权其他用户执行该函数。
pg_wal_replay_resume () → void 如果暂停了,则重新启动恢复。默认情况下该函数仅限超级用户使用,但可以授权其他用户执行该函数。

pg_wal_replay_pausepg_wal_replay_resume 不能在提升(promotion)进行时执行。 如果在恢复暂停时触发了提升(promotion),则暂停状态结束,升级继续进行。

如果禁用了流复制,则暂停状态可能会无限期地持续下去,不会出现问题。 如果正在进行流复制,那么将继续接收 WAL 记录,这将最终填满可用磁盘空间,这取决于暂停持续时间、WAL 生成速度和可用磁盘空间。

快照同步函数

AntDB 允许数据库会话同步它们的快照。一个快照决定对于正在使用该快照的事务哪些数据是可见的。当两个或者更多个会话需要看到数据库中的相同内容时,就需要同步快照。如果两个会话独立开始其事务,就总是有可能有某个第三事务在两个 START TRANSACTION 命令的执行之间提交,这样其中一个会话就可以看到该事务的效果而另一个则看不到。

为了解决这个问题,AntDB 允许一个事务导出它正在使用的快照。只要导出的事务仍然保持打开,其他事务可以导入它的快照,并且因此可以保证它们可以看到和第一个事务看到的完全一样的数据库视图。但是注意这些事务中的任何一个对数据库所作的更改对其他事务仍然保持不可见,和未提交事务所作的修改一样。因此这些事务是针对以前存在的数据同步,而对由它们自己所作的更改则采取正常的动作。

如下表中所示,快照通过 pg_export_snapshot 函数导出,并且通过 SET TRANSACTION 命令导入。

快照同步函数

函数描述
pg_export_snapshot () → text 保存事务的当前快照并返回 text 字符串以标识该快照。 必须将此字符串传递(在数据库之外)给希望导入快照的客户端。快照仅在导出它的事务结束之前才可用于导入。如果需要的话,一个事务可以导出多个快照。 请注意,这样做仅在 READ COMMITTED 事务中有用,因为在 REPEATABLE READ 和更高的隔离级别中,事务在它们的生命周期中使用相同的快照。 一旦事务导出了快照,它就不能用 PREPARE TRANSACTION 进行准备。

复制管理函数

下表中展示的函数用于控制以及与复制特性交互。复制原点函数的使用仅限于超级用户。 复制槽的函数只限于超级用户和拥有 REPLICATION 权限的用户。

复制管理函数

函数描述
pg_create_physical_replication_slot ( slot_name name [, immediately_reserve boolean, temporary boolean ] ) → record ( slot_name name, lsn pg_lsn ) 创建一个新的名为 slot_name 的物理复制槽。 第二个参数是可选的,当它为 true 时,立即为这个物理槽指定要被保留的 LSN。 否则该 LSN 会被保留在来自一个流复制客户端的第一个连接上。 当可选的第三参数 temporary 被设置为真时,指定那个槽不会被持久地存储在磁盘上并且仅对当前会话的使用有意义。 临时槽也会在发生任何错误时被释放。这个函数对应于复制协议命令 CREATE_REPLICATION_SLOT ... PHYSICAL
pg_drop_replication_slot ( slot_name name ) → void 丢弃名为 slot_name 的物理或逻辑复制槽。 和复制协议命令 DROP_REPLICATION_SLOT 相同。对于逻辑槽, 在连接到在其中创建该槽的同一个数据库时,必须调用这个函数。
pg_create_logical_replication_slot ( slot_name name, plugin name [, temporary boolean ] ) → record ( slot_name name, lsn pg_lsn ) 使用输出插件 plugin 创建一个名字为 slot_name 的新逻辑(解码)复制槽。 当可选的第三参数 temporary 被设置为真时,指定那个槽不会被持久地存储在磁盘上并且仅对当前会话的使用有意义。 临时槽也会在发生任何错误时被释放。对这个函数的调用与复制协议命令 CREATE_REPLICATION_SLOT ... LOGICAL
pg_copy_physical_replication_slot ( src_slot_name name, dst_slot_name name [, temporary boolean ] ) → record ( slot_name name, lsn pg_lsn ) 将一个名为 src_slot_name 的现有物理复制槽复制到一个名为 dst_slot_name 的物理复制槽。 被复制的物理槽开始从与源槽相同的 LSN 开始保留 WAL。temporary 是可选的。 如果省略了 temporary,则使用与源槽相同的值。
pg_copy_logical_replication_slot ( src_slot_name name, dst_slot_name name [, temporary boolean [, plugin name ]] ) → record ( slot_name name, lsn pg_lsn ) 复制一个名为 src_slot_name 的现有逻辑复制槽到一个名为 dst_slot_name 的逻辑复制槽,选择性的改变输出插件和持久性。 被复制的逻辑槽从与源逻辑槽相同的 LSN 开始。temporaryplugin 都是可选的。 如果它们被省略了,使用与源逻辑槽相同的值。
pg_logical_slot_get_changes ( slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] ) → setof record ( lsn pg_lsn, xid xid, data text ) 返回槽 slot_name 中的改变,从最后一次使用更改的点开始。 如果 upto_lsnupto_nchanges 为 NULL,逻辑解码将一直继续到 WAL 的末尾。 如果 upto_lsn 为非 NULL,解码将只包括那些在指定 LSN 之前提交的事务。 如果 upto_nchanges 为非 NULL,解码将在其产生的行数超过指定值后停止。 不过要注意,被返回的实际行数可能更大,因为对这个限制的检查只会在增加了解码每个新的提交事务产生的行之后进行。
pg_logical_slot_peek_changes ( slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] ) → setof record ( lsn pg_lsn, xid xid, data text ) 行为就像 pg_logical_slot_get_changes() 函数, 不过改变不会被消费, 即在未来的调用中还会返回这些改变。
pg_logical_slot_get_binary_changes ( slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] ) → setof record ( lsn pg_lsn, xid xid, data bytea ) 行为就像 pg_logical_slot_get_changes() 函数, 不过改变会以 bytea 返回。
pg_logical_slot_peek_binary_changes ( slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] ) → setof record ( lsn pg_lsn, xid xid, data bytea ) 行为就像 pg_logical_slot_peek_changes() 函数,不过改变会以 bytea 返回。
pg_replication_slot_advance ( slot_name name, upto_lsn pg_lsn ) → record ( slot_name name, end_lsn pg_lsn ) 将复制槽的当前确认的位置提前到名为 slot_name 的复制槽的当前确认位置。 该槽不会向后移动,也不会移动到当前插入位置之外。返回该槽的名称和它被推进到的真实位置。 如果有任何进展,则在下一个检查点中写出更新后的槽位置信息。所以如果发生崩溃,该槽位可能会返回到之前的位置。
pg_replication_origin_create ( node_name text ) → oid 用给定的外部名称创建一个复制源,并且返回分配给它的内部 ID。
pg_replication_origin_drop ( node_name text ) → void 删除一个以前创建的复制源,包括任何相关的重放进度。
pg_replication_origin_oid ( node_name text ) → oid 根据名称查找复制源并返回内部 ID。如果没有发现这样的复制源,则抛出错误。
pg_replication_origin_session_setup ( node_name text ) → void 将当前会话标记为从给定的原点回放,从而允许跟踪回放进度。 只能在当前没有选择原点时使用。使用 pg_replication_origin_session_reset 命令来撤销。
pg_replication_origin_session_reset () → void 取消 pg_replication_origin_session_setup() 的效果。
pg_replication_origin_session_is_setup () → boolean 如果在当前会话中选择了复制源则返回真。
pg_replication_origin_session_progress ( flush boolean ) → pg_lsn 返回当前会话中选择的复制源的重放位置。参数 flush 决定对应的本地事务是否被确保已经刷入磁盘。
pg_replication_origin_xact_setup ( origin_lsn pg_lsn, origin_timestamp timestamp with time zone ) → void 将当前事务标记为重放在给定 LSN 和时间戳上提交的事务。 只能在使用 pg_replication_origin_session_setup 选择复制源时调用。
pg_replication_origin_xact_reset () → void 取消 pg_replication_origin_xact_setup() 的效果。
pg_replication_origin_advance ( node_name text, lsn pg_lsn ) → void 将给定节点的复制进度设置为给定的位置。这主要用于设置初始位置,或在配置更改或类似的变更后设置新位置。 请注意这个函数的不当使用可能会导致不一致的复制数据。
pg_replication_origin_progress ( node_name text, flush boolean ) → pg_lsn 返回给定复制元的重放位置。参数 flush 决定对应的本地事务是否被确保已经刷入磁盘。
pg_logical_emit_message ( transactional boolean, prefix text, content text ) → pg_lsn``pg_logical_emit_message ( transactional boolean, prefix text, content bytea ) → pg_lsn 发出逻辑解码消息。这可以被用来通过 WAL 向逻辑解码插件传递一般消息。 transactional 参数指定该消息是否应该是当前事务的一部分或者当逻辑解码读到该记录时该消息是否应该被立刻写入并且解码。 prefix 参数是逻辑解码插件可以用来识别它们感兴趣的消息的文本前缀。content`* 是消息的文本,以文本或二进制形式给出。

数据库对象管理函数

下表中所示的函数计算数据库对象的磁盘空间使用情况,或帮助表示使用结果。 所有这些函数都返回以字节为单位的大小。如果将不代表已有对象的 OID 传递给这些函数之一,则返回 NULL

数据库对象尺寸函数

函数描述
pg_column_size ( "any" ) → integer 显示用于存储任何单个数据值的字节数。如果直接应用于表的列值,则反映所做的任何压缩。
pg_database_size ( name ) → bigint``pg_database_size ( oid ) → bigint 计算指定名称或 OID 的数据库所使用的总磁盘空间。 要使用这个函数,必须拥有 CONNECT 权限(默认授予)在指定的数据库上,或者是 pg_read_all_stats 角色的成员。
pg_indexes_size ( regclass ) → bigint 计算附加到指定表的索引所使用的总磁盘空间。
pg_relation_size ( relation regclass [, fork text ] ) → bigint 计算指定关系的一个“fork”所使用的磁盘空间。 (注意在大多数情况下,使用更高级的函数 pg_total_relation_sizepg_table_size 更方便,它们将所有分叉(forks)的大小相加。) 使用一个参数,这将返回关系的主数据分叉的大小。第二个参数可以用来指定要检查哪个分叉:main 返回关系的主数据分叉的大小。 fsm 返回与该关系关联的空闲空间映射的大小。vm 返回与该关系相关联的可见性映射的大小。init 返回初始化分叉的大小,如果有的话,与关系相关。
pg_size_bytes ( text ) → bigint 将人可阅读的格式的大小(由 pg_size_pretty 返回)转换为字节。
pg_size_pretty ( bigint ) → text``pg_size_pretty ( numeric ) → text 将以字节为单位的大小转换为更容易被人阅读的格式,使用大小单位(酌情采用字节、KB、MB、GB 或 TB 等等)。 注意,单位是 2 的幂,而不是 10 的幂,所以 1kB 是 1024 字节,1 MB 是 10242 = 1048576 字节,依此类推。
pg_table_size ( regclass ) → bigint 计算指定表所使用的磁盘空间,不包括索引(但包括它的 TOAST 表,如果有的话,空闲空间映射,以及可见性映射)。
pg_tablespace_size ( name ) → bigint``pg_tablespace_size ( oid ) → bigint 使用指定的名称或 OID 计算表空间中使用的总磁盘空间。 要使用这个函数,必须在指定的表空间上拥有 CREATE 权限,或者是 pg_read_all_stats 角色的成员,除非它是当前数据库的默认表空间。
pg_total_relation_size ( regclass ) → bigint 计算指定表所使用的总磁盘空间,包括所有索引和 TOAST 数据。 结果等价 pg_table_size + pg_indexes_size

上述操作表和索引的函数接受一个 regclass 参数,它是该表或索引在 pg_class 系统目录中的 OID。不必手工去查找该 OID,因为 regclass 数据类型的输入转换器会代劳。只写包围在单引号内的表名,这样它看起来像一个文字常量。为了与普通 SQL 名称的处理相兼容,该字符串将被转换为小写形式,除非其中在表名周围包含双引号。

数据库对象位置函数

函数描述
pg_relation_filenode ( relation regclass ) → oid 返回当前分配给指定关系的“filenode”数字。文件节点是用于该关系的文件名称的基本组件。 对于大多数关系,其结果与 pg_class.relfilenode 相同,但对于某些系统目录,relfilenode 为 0,并且必须使用这个函数来获得正确的值。 如果传递的是一个没有存储的关系,例如一个视图,那么函数将返回 NULL。
pg_relation_filepath ( relation regclass ) → text 返回关系的完整文件路径名称(相对于数据库集群的数据目录,关系的PGDATA)。
pg_filenode_relation ( tablespace oid, filenode oid ) → regclass 返回一个给定表空间 OID 和存储它的文件节点的关系的 OID。这本质上是 pg_relation_filepath 的反向映射。 对于数据库默认表空间中的关系,表空间可以指定为 0。如果当前数据库中没有与给定值相关联的关系,则返回 NULL

下表列出用于管理排序规则的函数。

排序规则管理函数

函数描述
pg_collation_actual_version ( oid ) → text 返回当前安装在操作系统中的该排序规则对象的实际版本。如果这个版本与 pg_collation.collversion 中的值不同,则依赖于该排序规则的对象可能需要被重建。
pg_import_system_collations ( schema regnamespace ) → integer 基于在操作系统中找到的所有区域环境(locales),加入排序规则到系统目录 pg_collation 中。 如果后来在操作系统上安装了额外的区域环境,可以再次运行这个函数加入新区域环境的排序规则。 匹配 pg_collation 中现有条目的区域环境将被跳过(但是这个函数不会移除以在操作系统中不再存在的区域环境为基础的排序规则对象)。 schema 参数通常是 pg_catalog,但这不是一种要求,排序规则也可以被安装到其他的方案中。 该函数返回其创建的新排序规则对象的数量。

下表列出提供有关分区表结构信息的函数。

分区信息函数

函数描述
pg_partition_tree ( regclass ) → setof record ( relid regclass, parentrelid regclass, isleaf boolean, level integer ) 列出给定分区表或分区索引的分区树中的表或索引,每行对应一个分区。 提供的信息包括分区的 OID、其直接父的 OID、一个布尔值以告知分区是否是叶子,以及一个整数用来告诉分区在层次结构中的级别。 对于输入表或索引,级别值为 0,其直接子分区的为 1,它们的分区为 2,以此类推。 如果关系不存在,或者不是分区或分区表,则不返回行。
pg_partition_ancestors ( regclass ) → setof regclass 列出给定分区的祖先关系,包括关系本身。如果关系不存在,或者不是分区或分区表,则不返回行。
pg_partition_root ( regclass ) → regclass 返回给定关系所属的分区树的最顶级父节点。如果关系不存在,或者不是分区或分区表,则返回 NULL

例如,要检查分区表 measurement 中包含的数据的总大小,可以使用以下查询:

SELECT pg_size_pretty(sum(pg_relation_size(relid))) AS total_size
  FROM pg_partition_tree('measurement');

索引维护函数

下表显示了索引维护任务可以使用的函数。 (注意,这些维护任务通常由自动清理(autovacuum)自动完成;只有在特殊情况下才需要使用这些函数。)这些函数在恢复过程中无法执行。这些函数的使用局限于超级用户和给定索引的所有者。

索引维护函数

函数描述
brin_summarize_new_values ( index regclass ) → integer 扫描指定的 BRIN 索引以查找基表中当前没有被索引归纳的页面范围; 对于任何这样的范围,它都通过扫描这些表页来创建一个新的摘要索引元组。 返回插入到索引中的新页面范围摘要的数量。
brin_summarize_range ( index regclass, blockNumber bigint ) → integer 归纳(Summarizes)覆盖给定块的页面范围(如果还没有归纳的话)。 这类似于brin_summarize_new_values,只是它只处理覆盖给定表块数的页范围。
brin_desummarize_range ( index regclass, blockNumber bigint ) → void删除归纳了覆盖给定表块的页面范围的 BRIN 索引元组,如果有的话。
gin_clean_pending_list ( index regclass ) → bigint 清理指定 GIN 索引的“pending”列表,通过移除里面的条目,以大批的方式,到主要的 GIN 数据结构。 返回从挂起列表中删除的页数。如果参数是使用禁用 fastupdate 选项构建的 GIN 索引,则不会发生清理,结果为零,因为索引没有挂起的列表。

通用文件访问函数

下表中展示的函数提供了对数据库服务器所在机器上的文件的本地访问。 只能访问数据库集簇目录以及 log_directory 中的文件,除非用户是超级用户或者被授予了角色 pg_read_server_files。 使用相对路径访问集簇目录里面的文件,以及匹配 log_directory 配置设置的路径访问日志文件。

注意在 pg_read_file() 或者相关函数上,向用户授予 EXECUTE 权限, 以允许他们有能力读取服务器上该数据库服务器进程能读取的任何文件;这些函数会绕过所有的数据库内权限检查。 这意味着,例如,具有这种访问的用户能够读取 pg_authid 表中存储着认证信息的内容,也能读取数据库中的任何表数据。 因此,授予对这些函数的访问应该要很仔细地考虑。

这些函数中的一些函数有可选的 missing_ok 参数,可以指定当文件或目录不存在时的行为。 如果为 true,函数返回 NULL 或着空结果集,根据适合情况。 如果为 false,会产生一个错误。默认为 false

通用文件访问函数

函数描述
pg_ls_dir ( dirname text [, missing_ok boolean, include_dot_dirs boolean ] ) → setof text 返回指定目录总所有文件(和目录以及其他指定文件)的名称。 include_dot_dirs 参数标示在结果集中是否包括“.” 和 “..”;默认为不包括它们。 要包括它们在 missing_oktrue 时能够有用,以从不存在的目录中辨别一个空目录。这个函数默认限制为超级用户,但是其他用户可以被授予 EXECUTE 以运行此函数。
pg_ls_logdir () → setof record ( name text, size bigint, modification timestamp with time zone ) 返回服务器的日志目录中的每个普通文件的名称、大小、和最后修改时间(mtime)。 文件名以一个点(dot)开始,目录和其他指定的文件不包括。这个函数默认限制在超级用户和 pg_monitor 角色的成员,但是其他用户可以被授予 EXECUTE 以运行此函数。
pg_ls_waldir () → setof record ( name text, size bigint, modification timestamp with time zone ) 返回服务器的预写式日志(WAL)目录中的每个普通文件的名称、大小、和最后修改时间(mtime)。 文件名以一个点(dot)开始,目录和其他指定的文件不包括。这个函数默认限制在超级用户和 pg_monitor 角色的成员,但是其他用户可以被授予 EXECUTE 以运行此函数。
pg_ls_archive_statusdir () → setof record ( name text, size bigint, modification timestamp with time zone ) 返回服务器的 WAL 归档状态目录(pg_wal/archive_status)中的每个普通文件的名称、大小、和最后修改时间(mtime)。 文件名以一个点(dot)开始,目录和其他指定的文件不包括。这个函数默认限制在超级用户和 pg_monitor 角色的成员,但是其他用户可以被授予 EXECUTE 以运行此函数。
pg_ls_tmpdir ( [ tablespace oid ] ) → setof record ( name text, size bigint, modification timestamp with time zone ) 返回针对指定 tablespace 的临时文件目录中的每个普通文件的名称、大小、和最后修改时间(mtime)。 如果 tablespace 没有提供,pg_default 表空间为被检验的。 文件名以一个点(dot)开始,目录和其他指定的文件不包括。这个函数默认限制在超级用户和 pg_monitor 角色的成员,但是其他用户可以被授予 EXECUTE 以运行此函数。
pg_read_file ( filename text [, offset bigint, length bigint [, missing_ok boolean ]] ) → text 返回一个文本文件的全部或部分,开始于给定的字节 offset,在最大的 length 字节返回(如果文件的结尾先达到了则减少)。 如果 offset 为负,他于文件的结尾有关。如果 offsetlength 被省略,整个文件被返回。 从文件中读的字节在服务器的编码中解释为字符串;如果它们在哪些编码中不是有效的则抛出错误。这个函数默认限制在超级用户,但是其他用户可以被授予 EXECUTE 以运行此函数。
pg_read_binary_file ( filename text [, offset bigint, length bigint [, missing_ok boolean ]] ) → bytea 返回文件的全部或部分。这个函数与 pg_read_file 是完全相同的,除了它可以读任意的二进制数据,返回结果为 bytea 而不是 text; 因此,没有编码检查会被执行。这个函数默认限制在超级用户,但是其他用户可以被授予 EXECUTE 以运行此函数。与 convert_from 函数组合,这个函数能被用于以指定的编码读文本文件并转换到数据库的编码:SELECT convert_from(pg_read_binary_file('file_in_utf8.txt'), 'UTF8');
pg_stat_file ( filename text [, missing_ok boolean ] ) → record ( size bigint, access timestamp with time zone, modification timestamp with time zone, change timestamp with time zone, creation timestamp with time zone, isdir boolean ) 返回一个记录,包含文件的大小、最后访问时间戳、最后修改时间戳,最后文件状态变更时间戳(仅在 UNIX 平台)、文件建立时间戳(仅 Windows)和一个标志旗如果它是一个目录。这个函数默认限制在超级用户,但是其他用户可以被授予 EXECUTE 以运行此函数。

咨询锁函数

下表中展示了函数管理咨询锁。

所有这些函数都打算用于锁定应用程序定义的资源,可以通过一个 64 位键值或两个 32 位键值来标识(注意这两个键空间不能重叠)。 如果另一个会话已经在相同的资源标识符上持有一个冲突的锁,函数将等待直到资源变成可用,或者返回一个 false 结果,合适于函数的。 锁可以是共享或排他的:共享锁不会与同一资源上的其他共享锁发生冲突,只会与排他锁发生冲突。 锁可以在会话级(这样它们被保持直到释放或会话结束)或在事务级(这样它们被保持直到当前事务结束;没有手动释放的供应)。 多个会话级锁请求堆栈,因此如果同一个资源标识符被锁定三次,那么必须有三个解锁请求来释放资源,在会话结束之前。

咨询锁函数

函数描述
pg_advisory_lock ( key bigint ) → void``pg_advisory_lock ( key1 integer, key2 integer ) → void 获取一个排他的会话级咨询锁,如有必要则等待。
pg_advisory_lock_shared ( key bigint ) → void``pg_advisory_lock_shared ( key1 integer, key2 integer ) → void 获取一个共享的会话级咨询锁,如有必要则等待。
pg_advisory_unlock ( key bigint ) → boolean``pg_advisory_unlock ( key1 integer, key2 integer ) → boolean 释放以前获取的排他会话级咨询锁。如果锁成功释放则返回 true。 如果锁没有被持有,则返回 false,此外,服务器将报告一个 SQL 警告。
pg_advisory_unlock_all () → void 释放当前会话所持有的所有会话级咨询锁。(即使客户端异常断开连接,这个函数也会在会话结束时被隐式调用。)
pg_advisory_unlock_shared ( key bigint ) → boolean``pg_advisory_unlock_shared ( key1 integer, key2 integer ) → boolean 释放以前获取的共享会话级咨询锁。如果锁成功释放则返回 true。 如果锁没有被持有,则返回 false,此外,服务器将报告一个 SQL 警告。
pg_advisory_xact_lock ( key bigint ) → void``pg_advisory_xact_lock ( key1 integer, key2 integer ) → void 获取一个排他的事务级咨询锁,如有必要则等待。
pg_advisory_xact_lock_shared ( key bigint ) → void``pg_advisory_xact_lock_shared ( key1 integer, key2 integer ) → void 获取一个共享的事务级咨询锁,如有必要则等待。
pg_try_advisory_lock ( key bigint ) → boolean``pg_try_advisory_lock ( key1 integer, key2 integer ) → boolean 获取一个排他的会话级咨询锁,如果适用。 这将立即获得锁并返回 true,或者如果不能立即获取锁则立即返回 false 而无需等待。
pg_try_advisory_lock_shared ( key bigint ) → boolean``pg_try_advisory_lock_shared ( key1 integer, key2 integer ) → boolean 获取一个共享的会话级咨询锁,如果适用。 这将立即获得锁并返回 true,或者如果不能立即获取锁则立即返回 false 而无需等待。
pg_try_advisory_xact_lock ( key bigint ) → boolean``pg_try_advisory_xact_lock ( key1 integer, key2 integer ) → boolean 获取一个排他的事务级咨询锁,如果适用。 这将立即获得锁并返回 true,或者如果不能立即获取锁则立即返回 false 而无需等待。
pg_try_advisory_xact_lock_shared ( key bigint ) → boolean``pg_try_advisory_xact_lock_shared ( key1 integer, key2 integer ) → boolean 获取一个共享的事务级咨询锁,如果适用。 这将立即获得锁并返回 true,或者如果不能立即获取锁则立即返回 false 而无需等待。

触发器函数

虽然很多触发器的使用都涉及到用户编写的触发器函数,但 AntDB 提供了一些可以直接在用户定义触发器中使用的内置触发器函数。(另外还有一些内置的触发器函数存在,它们实现了外键约束和延期索引约束。因为用户不需要直接使用它们,所以这里就不做论述了。)

内置触发器函数

函数描述Example Usage
suppress_redundant_updates_trigger ( ) → trigger 阻止不做事的更新操作。详见下文。CREATE TRIGGER ... suppress_redundant_updates_trigger()
tsvector_update_trigger ( ) → trigger 自动从相关的纯文本文档列更新 tsvector 列。 要使用的文本搜索配置是以名称指定为触发器参数。CREATE TRIGGER ... tsvector_update_trigger(tsvcol, 'pg_catalog.swedish', title, body)
tsvector_update_trigger_column ( ) → trigger 自动从相关的纯文本文档列更新 tsvector 列。要使用的文本搜索配置取自表的 regconfig 列。CREATE TRIGGER ... tsvector_update_trigger_column(tsvcol, tsconfigcol, title, body)

suppress_redundant_updates_trigger 函数,在作为行级 BEFORE UPDATE 触发器应用时,将阻止任何没有实际更改行中数据的更新发生。 这会覆盖那种始终执行物理行更新而无论数据是否已更改的常规行为。(这种常规的行为使更新运行得更快,因为不需要检查,而且在某些情况下也很有用。)

理想的情况下,应该避免运行实际上并没有改变记录中数据的更新。 冗余更新会花费大量不必要的时间,尤其是如果有大量索引要改变, 并将最终不得不清理被死亡行占用的空间。 但是,在客户端代码中检测这种情况并不总是容易的,甚至不可能做到。 而写表达式来检测它们容易产生错误。 作为替代,使用 suppress_redundant_updates_trigger 可以跳过不改变数据的更新。 但是,需要小心使用它。 触发器需要很短但不能忽略的时间来处理每条记录,所以如果受更新影响的大多数记录确实变化了,此触发器的使用将使更新比平均水平运行得更慢。

suppress_redundant_updates_trigger 函数可以像这样添加到表中:

CREATE TRIGGER z_min_update
BEFORE UPDATE ON tablename
FOR EACH ROW EXECUTE FUNCTION suppress_redundant_updates_trigger();

在大多数情况下,需要为每一行最后触发这个触发器,这样它就不会覆盖可能希望更改该行的其他触发器。 请记住,触发器是按照名称顺序触发的,将为此选择一个触发器名称,该名称位于表中可能存在的任何其他触发器的名称之后。 (因此在示例中使用了“z”前缀。)

事件触发器函数

在命令结束处捕捉更改

pg_event_trigger_ddl_commands () → setof record

当在一个 ddl_command_end 事件触发器的函数中调用时, pg_event_trigger_ddl_commands 返回被每一个用户动作 执行的 DDL 命令的列表。如果在其他任何环境中 调用这个函数,会发生错误。 pg_event_trigger_ddl_commands 为每一个被执行的基本 命令返回一行,某些只有一个单一 SQL 句子的命令可能会返回多于一行。 这个函数返回下面的列:

名称类型描述
classidoid对象所属的目录的 OID
objidoid对象本身的 OID
objsubidinteger对象的子 -id(例如列的属性号)
command_tagtext命令标签
object_typetext对象的类型
schema_nametext该对象所属的模式的名称(如果有),如果没有则为 NULL。 没有引号。
object_identitytext对象标识的文本表现形式,用模式限定。如果必要,出现在 该标识中的每一个标识符都会被引用。
in_extensionboolean如果该命令是一个扩展脚本的一部分则为真
commandpg_ddl_command以内部格式表达的该命令的一个完整表现形式。这不能被直接输出, 但是可以把它传递给其他函数来得到有关于该命令不同部分的信息。

处理被 DDL 命令删除的对象

pg_event_trigger_dropped_objects () → setof record

pg_event_trigger_dropped_objects 返回被调用 sql_drop 事件的命令删除的所有对象的列表。如果调用在任何其他上下文中,会引发一个错误。这个函数返回以下列:

名称类型描述
classidoid对象所属的目录的 OID
objidoid对象本身的 OID
objsubidinteger子对象 ID(如列的属性号)
originalboolean如果这是删除中的一个根对象则为真
normalboolean指示在依赖图中有一个普通依赖关系指向该对象的标志
is_temporaryboolean如果该对象是一个临时对象则为真
object_typetext对象的类型
schema_nametext对象所属模式的名称(如果存在);否则为 NULL。不应用引用。
object_nametext如果模式和名称的组合能被用于对象的一个唯一标识符,则是对象的名称;否则是 NULL。不应用引用,并且名称不是模式限定的。
object_identitytext对象身份的文本表现,模式限定的。每一个以及所有身份中出现的标识符在必要时加引号。
address_namestext[]一个数组,它可以和 object_typeaddress_args, 一起通过 pg_get_object_address 函数在一台包含有同类相同名称对象的远程服务器上重建该对象地址。
address_argstext[]上述 address_names 的补充。

pg_event_trigger_dropped_objects 可以被这样用在一个事件触发器中:

CREATE FUNCTION test_event_trigger_for_drops()
        RETURNS event_trigger LANGUAGE plpgsql AS $$
DECLARE
    obj record;
BEGIN
    FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects()
    LOOP
        RAISE NOTICE '% dropped object: % %.% %',
                     tg_tag,
                     obj.object_type,
                     obj.schema_name,
                     obj.object_name,
                     obj.object_identity;
    END LOOP;
END;
$$;
CREATE EVENT TRIGGER test_event_trigger_for_drops
   ON sql_drop
   EXECUTE FUNCTION test_event_trigger_for_drops();

处理表重写事件

下表中所示的函数提供刚刚被调用过 table_rewrite 事件的表的信息。如果在任何其他环境中调用,会发生错误。

表重写信息函数

函数描述
pg_event_trigger_table_rewrite_oid () → oid 返回将要重写的表的 OID。
pg_event_trigger_table_rewrite_reason () → integer 返回解释重写原因的代码。代码的确切含义取决于版本。

这些函数可以在事件触发器中使用,就像这样:

CREATE FUNCTION test_event_trigger_table_rewrite_oid()
 RETURNS event_trigger
 LANGUAGE plpgsql AS
$$
BEGIN
  RAISE NOTICE 'rewriting table % for reason %',
                pg_event_trigger_table_rewrite_oid()::regclass,
                pg_event_trigger_table_rewrite_reason();
END;
$$;

CREATE EVENT TRIGGER test_table_rewrite_oid
                  ON table_rewrite
   EXECUTE FUNCTION test_event_trigger_table_rewrite_oid();

统计信息函数

pg_mcv_list_items ( pg_mcv_list ) → setof record

pg_mcv_list_items 返回一组记录,描述存储在多列 MCV 列表中的所有项目。它返回以下列:

名称类型描述
indexintegerMCV 列表中的项目索引
valuestext[]存储在 MCV 项目中的值
nullsboolean[]标识 NULL 值的标志
frequencydouble precisionMCV 项目的频率
base_frequencydouble precisionMCV 项目的基本频率

pg_mcv_list_items 函数可以这样使用:

SELECT m.* FROM pg_statistic_ext join pg_statistic_ext_data on (oid = stxoid),
                pg_mcv_list_items(stxdmcv) m WHERE stxname = 'stts';

pg_mcv_list 类型的值只能从 pg_statistic_ext_data.stxdmcv 列中获取。

问题反馈