1、词法结构
SQL输入由一个命令序列组成。
一个命令由一个记号的序列构成,并由一个分号(“;”)终结。
一个记号可以是一个关键词、一个标识符、一个带引号的标识符、一个literal(或常量)或者一个特殊字符符号。
记号通常以空白(空格、制表符、新行)来分隔,但在无歧义时并不强制要求如此(唯一的例子是一个特殊字符紧挨着其他记号)。
另外,注释也可以出现在SQL输入中。它们不是记号,它们和空白完全一样。
根据标识命令、操作符、参数的记号不同,SQL的语法不很一致。最前面的一些记号通常是命令名,我们通常会说一个“SELECT”、一个“UPDATE”和一个“INSERT”命令。
但是例如UPDATE命令总是要求一个SET记号出现在一个特定位置,而INSERT则要求一个VALUES来完成命令。
1.1. 标识符和关键词
SQL标识符和关键词必须以一个字母(a-z,也可以是带变音符的字母和非拉丁字母)或一个下划线()开始。后续字符可以是字母、下划线()、数字(0-9)或美元符号($)。
美元符号是不允许出现在标识符中的。
系统中一个标识符的长度不能超过 NAMEDATALEN-1 字节,在命令中可以写超过此长度的标识符,但是它们会被截断。默认情况下,NAMEDATALEN 的值为64,因此标识符的长度上限为63字节。如果这个限制有问题,可以在include/pg_config_manual.h中修改 NAMEDATALEN 常量。
一个常见的习惯是将关键词写成大写,而名称写成小写。
第二种形式的标识符:受限标识符或被引号修饰的标识符。它是由双引号(")包围的一个任意字符序列。一个受限标识符总是一个标识符而不会是一个关键字。因此"select"可以用于引用一个名为“select”的列或者表,而一个没有引号修饰的select则会被当作一个关键词,从而在本应使用表或列名的地方引起解析错误。
受限标识符可以包含任何字符,除了代码为0的字符(如果要包含一个双引号,则写两个双引号)。
1.2. 常量
在PostgreSQL中有三种隐式类型常量:字符串、位串和数字。
字符串常量
在SQL中,一个字符串常量是一个由单引号(‘)包围的任意字符序列,例如’This is a string’。
为了在一个字符串中包括一个单引号,可以写两个相连的单引号,例如’Dianne’‘s horse’。
两个只由空白及至少一个新行分隔的字符串常量会被连接在一起,并且将作为一个写在一起的字符串常量来对待。
ELECT 'foo'
'bar';
等同于:
SELECT 'foobar';
但是:
SELECT 'foo' 'bar';
则不是合法的语法
也接受“转义”字符串常量,这也是SQL标准的一个扩展。一个转义字符串常量可以通过在开单引号前面写一个字母E(大写或小写形式)来指定。
位串常量
位串常量看起来像常规字符串常量在开引号之前(中间无空白)加了一个B(大写或小写形式),例如B’1001’。位串常量中允许的字符只有0和1。
数字常量
在这些一般形式中可以接受数字常量:
digits
digits.[digits][e[+-]digits]
[digits].digits[e[+-]digits]
digitse[+-]digits
其中digits是一个或多个十进制数字(0 到 9)。
如果使用了小数点,在小数点前面或后面必须至少有一个数字。
如果存在一个指数标记(e),在其后必须跟着至少一个数字。
在该常量中不能嵌入任何空白或其他字符。注意任何前导的加号或减号并不实际被考虑为常量的一部分,它是一个应用到该常量的操作符。
这些是合法数字常量的例子:
42
3.5
4.
.001
5e2
1.925e-3
美元字符常量
PostgreSQL提供了另一种被称为“美元引用”的方式来书写字符串常量。
一个美元引用的字符串常量由一个美元符号($)、一个可选的另个或更多字符的“标签”、另一个美元符号、一个构成字符串内容的任意字符序列、一个美元符号、开始这个美元引用的相同标签和一个美元符号组成。
例如,这里有两种不同的方法使用美元引用指定字符串“Dianne’s horse”:
$$Dianne's horse$$
$SomeTag$Dianne's horse$SomeTag$
可以通过在每一个嵌套级别上选择不同的标签来嵌套美元引用字符串常量。这最常被用在编写函数定义上。例如:
$function$
BEGIN
RETURN ($1 ~ $q$[\t\r\n\v\\]$q$);
END;
$function$
这里,序列$q$[\t\r\n\v\]$q$表示一个美元引用的文字串[\t\r\n\v\],当该函数体被PostgreSQL执行时它将被识别。但是因为该序列不匹配外层的美元引用的定界符$function$,它只是一些在外层字符串所关注的常量中的字符而已。
一个美元引用字符串的标签(如果有)遵循一个未被引用标识符的相同规则,除了它不能包含一个美元符号之外。标签是大小写敏感的,因此$tag$String content$tag$是正确的,但是$TAG$String content$tag$不正确。
一个跟着一个关键词或标识符的美元引用字符串必须用空白与之分隔开,否则美元引用定界符可能会被作为前面标识符的一部分
1.3. 操作符
一个操作符名是最多NAMEDATALEN-1(默认为 63)的一个字符序列,其中的字符来自下面的列表:
+ - * / < > = ~ ! @ # % ^ & | ` ?不过,在操作符名上有一些限制:
-- and /*不能在一个操作符名的任何地方出现,因为它们将被作为一段注释的开始。
一个多字符操作符名不能以+或-结尾,除非该名称也至少包含这些字符中的一个:
~ ! @ # % ^ & | ` ?
例如,@-是一个被允许的操作符名,但*-不是。这些限制允许PostgreSQL解析 SQL 兼容的查询而不需要在记号之间有空格。
1.4. 特殊字符
一些不是数字字母的字符有一种不同于作为操作符的特殊含义。
跟随在一个美元符号($)后面的数字被用来表示在一个函数定义或一个预备语句中的位置参数。在其他上下文中该美元符号可以作为一个标识符或者一个美元引用字符串常量的一部分。
圆括号(())具有它们通常的含义,用来分组表达式并且强制优先。
方括号([])被用来选择一个数组中的元素。
逗号(,)被用在某些语法结构中来分割一个列表的元素。
分号(;)结束一个 SQL 命令。它不能出现在一个命令中间的任何位置,除了在一个字符串常量中或者一个被引用的标识符中。
冒号(:)被用来从数组中选择“切片”。
星号(*)被用在某些上下文中标记一个表的所有域或者组合值。当它被用作一个聚集函数的参数时,它还有一种特殊的含义,即该聚集不要求任何显式参数。
句点(.)被用在数字常量中,并且被用来分割模式、表和列名。
1.5. 注释
一段注释是以双横杠开始并且延伸到行结尾的一个字符序列。
1.6. 操作符优先级
大部分操作符具有相同的优先并且是左结合的。操作符的优先级和结合性被硬写在解析器中。 如果您希望以不同于优先级规则所暗示的方式解析具有多个运算符的表达式,请添加括号。
操作符优先级(从高到低)
操作符/元素 | 结 合 性 | 描述 |
---|---|---|
. | 左 | 表/列名分隔符 |
:: | 左 | PostgreSQL-风格的类型转换 |
[ ] | 左 | 数组元素选择 |
+ - | 右 | 一元加、一元减 |
^ | 左 | 指数 |
* / % | 左 | 乘、除、模 |
+ - | 左 | 加、减 |
(任意其他操作符) | 左 | 所有其他本地以及用户定义的操作符 |
BETWEEN IN LIKE ILIKE SIMILAR | 范围包含、集合成员关系、字符串匹配 | |
< > = <= >= <> | 比较操作符 | |
IS ISNULL NOTNULL | IS TRUE、IS FALSE、IS NULL、IS DISTINCT FROM等 | |
NOT | 右 | 逻辑否定 |
AND | 左 | 逻辑合取 |
OR | 左 | 逻辑析取 |
注意该操作符有限规则也适用于与上述内建操作符具有相同名称的用户定义的操作符。
例如,如果你为某种自定义数据类型定义了一个“+”操作符,它将具有和内建的“+”操作符相同的优先级,不管你的操作符要做什么。
当一个模式限定的操作符名被用在OPERATOR语法中时,如下面的例子:
SELECT 3 OPERATOR(pg_catalog.+) 4;
OPERATOR结构被用来为“任意其他操作符”获得默认的优先级。
不管出现在OPERATOR()中的是哪个指定操作符。