2025年9月25日: PostgreSQL 18 釋出!
支援的版本: 當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本: devel
不支援的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2

4.1. 詞法結構 #

SQL 輸入由一系列 命令 組成。一個命令由一系列 標記 組成,以分號(;)結束。輸入流的末尾也結束一個命令。哪些標記是有效的取決於特定命令的語法。

標記可以是 關鍵字識別符號帶引號識別符號字面量(或常量),或特殊符號。標記通常由空格(空格、製表符、換行符)分隔,但如果沒有歧義(通常只有當特殊字元與其他標記型別相鄰時才會發生)則不必如此。

例如,以下是(語法上)有效的 SQL 輸入

SELECT * FROM MY_TABLE;
UPDATE MY_TABLE SET A = 5;
INSERT INTO MY_TABLE VALUES (3, 'hi there');

這是一個由三個命令組成的序列,每個命令佔一行(儘管這不是必需的;一行可以包含多個命令,並且命令可以方便地跨行分割)。

此外,註釋 可以出現在 SQL 輸入中。它們不是標記,它們基本上等同於空格。

SQL 語法在哪些標記標識命令和哪些標記是運算元或引數方面不太一致。最前面的幾個標記通常是命令名稱,因此在上面的例子中,我們通常會談論一個 SELECT 命令、一個 UPDATE 命令和一個 INSERT 命令。但例如 UPDATE 命令總是需要一個 SET 標記出現在特定位置,而這個特定變體的 INSERT 也需要一個 VALUES 才能完整。每個命令的精確語法規則在 VI. 部分 參考 中描述。

4.1.1. 識別符號和關鍵字 #

上面示例中的 SELECTUPDATEVALUES 等標記是 關鍵字 的示例,也就是說,在 SQL 語言中有固定含義的詞。標記 MY_TABLEA識別符號 的示例。它們根據它們所使用的命令來標識表、列或其他資料庫物件的名稱。因此,它們有時被稱為 名稱。關鍵字和識別符號具有相同的詞法結構,這意味著不瞭解語言就無法知道一個標記是識別符號還是關鍵字。關鍵字的完整列表可在 附錄 C 中找到。

SQL 識別符號和關鍵字必須以字母(a-z,也包括帶音標的字母和非拉丁字母)或下劃線(_)開頭。識別符號或關鍵字中的後續字元可以是字母、下劃線、數字(0-9)或美元符號($)。請注意,根據 SQL 標準的字面意思,不允許在識別符號中使用美元符號,因此它們的用法可能會降低應用程式的可移植性。SQL 標準不會定義包含數字或以數字或下劃線開頭或結尾的關鍵字,因此此形式的識別符號可以避免與標準未來擴充套件的潛在衝突。

系統使用的識別符號長度不超過 NAMEDATALEN-1 位元組;可以寫更長的名稱,但它們將被截斷。預設情況下,NAMEDATALEN 為 64,因此最大識別符號長度為 63 位元組。如果此限制有問題,可以透過修改 src/include/pg_config_manual.h 中的 NAMEDATALEN 常量來提高它。

關鍵字和未加引號的識別符號不區分大小寫。因此

UPDATE MY_TABLE SET A = 5;

可以等效地寫成

uPDaTE my_TabLE SeT a = 5;

一個常用的約定是將關鍵字寫成大寫,將名稱寫成小寫,例如

UPDATE my_table SET a = 5;

還有第二種識別符號:分隔識別符號帶引號識別符號。它透過將任意字元序列括在雙引號(")中形成。分隔識別符號始終是識別符號,從不是關鍵字。因此 "select" 可用於引用名為 select 的列或表,而未加引號的 select 將被視為關鍵字,因此在期望表或列名稱的位置使用時會引發解析錯誤。示例可以這樣寫,使用帶引號的識別符號

UPDATE "my_table" SET "a" = 5;

帶引號識別符號可以包含除零程式碼字元外的任何字元。(要包含雙引號,請寫兩個雙引號。)這允許構建否則不可能的表或列名稱,例如包含空格或與符號的名稱。長度限制仍然適用。

引用識別符號也會使其區分大小寫,而未加引號的名稱總是會被摺疊成小寫。例如,識別符號 FOOfoo"foo"PostgreSQL 中被視為相同,但 "Foo""FOO" 與這三個以及它們彼此之間都不同。(PostgreSQL 中未加引號的名稱摺疊成小寫與 SQL 標準不相容,標準規定未加引號的名稱應摺疊成大寫。因此,根據標準,foo 應等同於 "FOO" 而不是 "foo"。如果要編寫可移植的應用程式,建議始終引用特定名稱或從不引用它。)

帶引號識別符號的變體允許包含由其程式碼點標識的轉義 Unicode 字元。該變體以 U&(大寫或小寫 U 後跟 ampersand)開頭,緊接在開頭的雙引號之前,中間沒有空格,例如 U&"foo"。(請注意,這會與運算子 & 產生歧義。在運算子周圍使用空格以避免此問題。)在引號內,可以透過寫入反斜槓後跟四位十六進位制程式碼點數字,或另一種選擇是反斜槓後跟加號後跟六位十六進位制程式碼點數字來指定 Unicode 字元的轉義形式。例如,識別符號 "data" 可以寫成

U&"d\0061t\+000061"

下面的一個不太簡單的例子用西裡爾字母寫了俄語單詞 slon(大象)

U&"\0441\043B\043E\043D"

如果需要一個不同於反斜槓的跳脫字元,可以使用字串後的 UESCAPE 子句,例如

U&"d!0061t!+000061" UESCAPE '!'

跳脫字元可以是除十六進位制數字、加號、單引號、雙引號或空格字元以外的任何單個字元。請注意,跳脫字元寫在 UESCAPE 之後的單引號中,而不是雙引號中。

要將跳脫字元本身字面包含在識別符號中,請寫兩次。

可以使用四位或六位轉義形式來指定 UTF-16 代替對以構成程式碼點大於 U+FFFF 的字元,儘管六位形式的存在使得這在技術上不必要。(替代對不會直接儲存,而是組合成單個程式碼點。)

如果伺服器編碼不是 UTF-8,則由這些轉義序列之一標識的 Unicode 程式碼點將轉換為實際伺服器編碼;如果無法轉換,則會報告錯誤。

4.1.2. 常量 #

PostgreSQL 中有三種 隱式型別常量:字串、位串和數字。常量也可以指定顯式型別,這可以實現更準確的表示和更高效的系統處理。這些選擇將在接下來的子節中討論。

4.1.2.1. 字串常量 #

SQL 中的字串常量是用單引號(')界定的任意字元序列,例如 'This is a string'。要在字串常量中包含單引號字元,請寫兩個相鄰的單引號,例如 'Dianne''s horse'。請注意,這與雙引號字元("不同

僅由空格分隔的兩個字串常量(至少包含一個換行符)將被連線起來,並有效地被視為字串作為一個常量寫入。例如

SELECT 'foo'
'bar';

等同於

SELECT 'foobar';

但是

SELECT 'foo'      'bar';

不是有效語法。(這種略顯奇怪的行為是由SQL指定的;PostgreSQL 遵循標準。)

4.1.2.2. 帶 C 風格轉義的字串常量 #

PostgreSQL 還接受 轉義 字串常量,這是對 SQL 標準的擴充套件。跳脫字元串常量透過在開頭的單引號前寫字母 E(大寫或小寫)來指定,例如 E'foo'。(當跨行繼續跳脫字元串常量時,僅在第一個開頭的引號前寫 E。)在跳脫字元串中,反斜槓字元(\)開始一個類似 C 的 反斜槓轉義序列,其中反斜槓和後續字元的組合表示一個特殊位元組值,如 表 4.1 所示。

表 4.1. 反斜槓轉義序列

反斜槓轉義序列 解釋
\b 退格
\f 換頁
\n 換行
\r 回車
\t 製表符
\o\oo\oooo = 0–7) 八進位制位元組值
\xh\xhhh = 0–9,A–F) 十六進位制位元組值
\uxxxx\Uxxxxxxxxx = 0–9,A–F) 16 位或 32 位十六進位制 Unicode 字元值

反斜槓後面的任何其他字元都將被視為字面字元。因此,要包含反斜槓字元,請寫兩個反斜槓(\\)。另外,單引號可以透過寫 \' 來包含在跳脫字元串中,除了通常的 '' 方法。

您有責任確保您建立的位元組序列,尤其是在使用八進位制或十六進位制轉義時,組成伺服器字元集編碼中的有效字元。一個有用的替代方法是使用 Unicode 轉義或替代 Unicode 轉義語法,如 4.1.2.3. 帶 Unicode 轉義的字串常量 所述;然後伺服器將檢查字元轉換是否可能。

注意

如果配置引數 standard_conforming_stringsoff,則 PostgreSQL 會在常規字串常量和跳脫字元串常量中都識別反斜槓轉義。然而,從 PostgreSQL 9.1 開始,預設值為 on,這意味著反斜槓轉義僅在跳脫字元串常量中識別。這種行為更符合標準,但可能會破壞依賴於歷史行為(反斜槓轉義始終被識別)的應用程式。作為一種變通方法,您可以將此引數設定為 off,但最好放棄使用反斜槓轉義。如果您需要使用反斜槓轉義來表示特殊字元,請使用 E 來寫字串常量。

除了 standard_conforming_strings 之外,配置引數 escape_string_warningbackslash_quote 控制了字串常量中反斜槓的處理。

程式碼為零的字元不能在字串常量中。

4.1.2.3. 帶 Unicode 轉義的字串常量 #

PostgreSQL 還支援另一種轉義語法,用於字串,允許透過程式碼點指定任意 Unicode 字元。Unicode 跳脫字元串常量以 U&(大寫或小寫字母 U 後跟 ampersand)開頭,緊接在開頭的引號之前,中間沒有空格,例如 U&'foo'。(請注意,這會與運算子 & 產生歧義。在運算子周圍使用空格以避免此問題。)在引號內,可以透過寫入反斜槓後跟四位十六進位制程式碼點數字,或另一種選擇是反斜槓後跟加號後跟六位十六進位制程式碼點數字來指定 Unicode 字元的轉義形式。例如,字串 'data' 可以寫成

U&'d\0061t\+000061'

下面的一個不太簡單的例子用西裡爾字母寫了俄語單詞 slon(大象)

U&'\0441\043B\043E\043D'

如果需要一個不同於反斜槓的跳脫字元,可以使用字串後的 UESCAPE 子句,例如

U&'d!0061t!+000061' UESCAPE '!'

跳脫字元可以是除十六進位制數字、加號、單引號、雙引號或空格字元以外的任何單個字元。

要將跳脫字元本身字面包含在字串中,請寫兩次。

可以使用四位或六位轉義形式來指定 UTF-16 代替對以構成程式碼點大於 U+FFFF 的字元,儘管六位形式的存在使得這在技術上不必要。(替代對不會直接儲存,而是組合成單個程式碼點。)

如果伺服器編碼不是 UTF-8,則由這些轉義序列之一標識的 Unicode 程式碼點將轉換為實際伺服器編碼;如果無法轉換,則會報告錯誤。

此外,Unicode 轉義語法僅在配置引數 standard_conforming_strings 開啟時才對字串常量有效。這是因為否則此語法可能會混淆解析 SQL 語句的客戶端,從而導致 SQL 注入和類似的安全問題。如果引數設定為 off,此語法將被拒絕並顯示錯誤訊息。

4.1.2.4. 美元引用字串常量 #

雖然指定字串常量的標準語法通常很方便,但在所需字串包含大量單引號時,它可能難以理解,因為每個單引號都必須加倍。為了在這種情況下允許更易讀的查詢,PostgreSQL 提供了另一種稱為 美元引用 的方式來書寫字串常量。美元引用字串常量由一個美元符號($)、一個零個或多個字元的可選 標籤、另一個美元符號、構成字串內容的任意字元序列、一個美元符號、開始此美元引用的相同標籤,以及一個美元符號組成。例如,以下是兩種使用美元引用書寫字串 Dianne's horse 的不同方式

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

請注意,在美元引用字串內部,單引號可以不轉義就被使用。事實上,美元引用字串中的任何字元都不會被轉義:字串內容始終按字面形式書寫。反斜槓不是特殊的,美元符號也不是,除非它們是匹配起始標籤的序列的一部分。

可以透過選擇不同巢狀級別的標籤來巢狀美元引用字串常量。這在編寫函式定義時最常用。例如

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

在此,序列 $q$[\t\r\n\v\\]$q$ 表示一個美元引用字面字串 [\t\r\n\v\\],當函式體由 PostgreSQL 執行時將被識別。但由於該序列不匹配外部美元引用分隔符 $function$,因此對於外部字串而言,它只是常量中的更多字元。

美元引用字串的標籤(如果存在)遵循與未加引號識別符號相同的規則,除了它不能包含美元符號。標籤區分大小寫,因此 $tag$String content$tag$ 是正確的,而 $TAG$String content$tag$ 則不是。

緊跟在關鍵字或識別符號後面的美元引用字串必須用空格與其分隔;否則,美元引用分隔符將被視為前一個識別符號的一部分。

美元引用不是 SQL 標準的一部分,但它通常比符合標準的單引號語法更方便地書寫複雜的字串字面量。當表示過程函式定義中經常需要的其他常量內的字串常量時,它特別有用。使用單引號語法,上面示例中的每個反斜槓都必須寫成四個反斜槓,這在解析原始字串常量時將被減少為兩個反斜槓,然後當內部字串常量在函式執行期間重新解析時將被減少為一個。

4.1.2.5. 位字串常量 #

位字串常量看起來像常規字串常量,在開頭的引號前(無中間空格)有一個 B(大寫或小寫),例如 B'1001'。位字串常量中允許的唯一字元是 01

或者,可以使用十六進位制表示法指定位字串常量,使用前導 X(大寫或小寫),例如 X'1FF'。此表示法等同於位字串常量,每個十六進位制數字對應四個二進位制數字。

位字串常量的這兩種形式都可以像常規字串常量一樣跨行繼續。美元引用不能在位字串常量中使用。

4.1.2.6. 數字常量 #

數字常量接受以下一般形式

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

其中 digits 是一個或多個十進位制數字(0 到 9)。如果使用了小數點,則小數點前或後必須至少有一個數字。如果存在指數標記(e),則其後必須至少有一個數字。常量中不能有任何空格或其他字元,但可以使用下劃線進行視覺分組,如下所述。請注意,任何前導的正號或負號實際上不被視為常量的一部分;它們是應用於常量的運算子。

以下是一些有效的數字常量的示例


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

此外,非十進位制整數常量接受以下形式

0xhexdigits
0ooctdigits
0bbindigits

其中 hexdigits 是一個或多個十六進位制數字(0-9,A-F),octdigits 是一個或多個八進位制數字(0-7),bindigits 是一個或多個二進位制數字(0 或 1)。十六進位制數字和基數字首可以是大小寫。請注意,只有整數可以採用非十進位制形式,而帶小數部分的數字則不能。

以下是一些有效的非十進位制整數常量的示例


0b100101
0B10011001
0o273
0O755
0x42f
0XFFFF

為了視覺分組,可以在數字之間插入下劃線。這些下劃線對常量的值沒有其他影響。例如


1_500_000_000
0b10001000_00000000
0o_1_755
0xFFFF_FFFF
1.618_034

不允許在數字常量或數字分組的開頭或結尾(即小數點或指數標記之前或之後)使用下劃線,並且不允許連續使用多個下劃線。

不包含小數點或指數的數字常量最初被假定為 integer 型別(如果其值適合 integer 型別(32 位));否則,如果其值適合 bigint 型別(64 位),則被假定為 bigint 型別;否則,則被視為 numeric 型別。包含小數點和/或指數的常量始終被最初假定為 numeric 型別。

數字常量的初始分配資料型別只是型別解析演算法的起點。在大多數情況下,常量將根據上下文自動強制轉換為最合適的型別。必要時,您可以透過強制轉換來強制將數字值解釋為特定資料型別。 例如,您可以透過編寫以下內容將數字值強制轉換為 realfloat4)型別

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

這些實際上只是稍後討論的一般強制轉換表示法的特殊情況。

4.1.2.7. 其他型別常量 #

可以按以下任一方式輸入 任意 型別的常量

type 'string'
'string'::type
CAST ( 'string' AS type )

字串常量的文字將傳遞給 type 型別的輸入轉換例程。結果是指定型別的常量。如果常量的型別沒有歧義(例如,當它直接分配給表列時),則可以省略顯式型別轉換,在這種情況下它會自動強制轉換。

可以使用常規 SQL 表示法或美元引用來編寫字串常量。

也可以使用類似函式的語法指定型別轉換

typename ( 'string' )

但並非所有型別名稱都可用於此方式;有關詳細資訊,請參閱 4.2.9. 型別轉換

::CAST() 和函式呼叫語法也可用於指定任意表達式的執行時型別轉換,如 4.2.9. 型別轉換 中所述。為避免語法歧義,type 'string' 語法只能用於指定簡單字面常量。另一個限制是 type 'string' 語法不適用於陣列型別;要指定陣列常量的型別,請使用 ::CAST()

CAST() 語法符合 SQL。 type 'string' 語法是標準的泛化:SQL 僅為少數資料型別指定了此語法,但 PostgreSQL 允許所有型別使用它。:: 語法是歷史上的 PostgreSQL 用法,函式呼叫語法也是如此。

4.1.3. 運算子 #

運算子名稱是由以下列表中的最多 NAMEDATALEN-1(預設為 63)個字元組成的序列


+ - * / < > = ~ ! @ # % ^ & | ` ?

但是,運算子名稱有一些限制

  • --/* 不能出現在運算子名稱的任何地方,因為它們將被視為註釋的開始。

  • 多字元運算子名稱不能以 +- 結尾,除非該名稱還包含至少一個這些字元


    ~ ! @ # % ^ & | ` ?

    例如,@- 是允許的運算子名稱,但 *- 則不是。此限制允許 PostgreSQL 解析符合 SQL 的查詢,而無需在標記之間新增空格。

在使用非 SQL 標準運算子名稱時,通常需要用空格分隔相鄰的運算子以避免歧義。例如,如果您定義了一個名為 @ 的字首運算子,您不能寫 X*@Y;您必須寫 X* @Y 以確保 PostgreSQL 將其讀取為兩個運算子名稱而不是一個。

4.1.4. 特殊字元 #

一些非字母數字字元具有與運算子不同的特殊含義。有關用法的詳細資訊可以在描述相應語法元素的地點找到。本節僅用於告知這些字元的存在並總結它們的目的。

  • 一個美元符號($)後跟數字用於表示函式定義或準備語句體中的位置引數。在其他上下文中,美元符號可以是識別符號或美元引用字串常量的一部分。

  • 括號(())用於分組表示式和強制優先順序。在某些情況下,括號是特定 SQL 命令固定語法的一部分。

  • 方括號([])用於選擇陣列的元素。有關陣列的更多資訊,請參閱 8.15. 陣列

  • 逗號(,)在某些語法結構中用於分隔列表的元素。

  • 分號(;)用於終止 SQL 命令。它不能出現在命令的任何地方,除了字串常量或帶引號識別符號內部。

  • 冒號(:)用於從陣列中選擇 切片。(請參閱 8.15. 陣列。)在某些 SQL 方言(如嵌入式 SQL)中,冒號用於字首變數名。

  • 星號(*)在某些上下文中用於表示錶行或複合值的全部欄位。當用作聚合函式的引數時,它也有特殊含義,即聚合不需要顯式引數。

  • 句點(.)用於數字常量,並用於分隔模式、表和列名。

4.1.5. 註釋 #

註釋是beginning with double dashes and extending to the end of the line 的字元序列,例如

-- This is a standard SQL comment

或者,可以使用 C 風格的塊註釋

/* multiline comment
 * with nesting: /* nested block comment */
 */

其中註釋以 /* 開頭,並一直到匹配的 */。這些塊註釋是巢狀的,如 SQL 標準所指定,但與 C 不同,因此可以註釋掉可能包含現有塊註釋的大塊程式碼。

註釋在進一步的語法分析之前從輸入流中移除,並有效地替換為空格。

4.1.6. 運算子優先順序 #

表 4.2 顯示了 PostgreSQL 中運算子的優先順序和關聯性。大多數運算子具有相同的優先順序,並且是左關聯的。運算子的優先順序和關聯性已硬編碼到解析器中。如果您希望包含多個運算子的表示式以不同於優先順序規則暗示的方式進行解析,請新增括號。

表 4.2. 運算子優先順序(從高到低)

運算子/元素 關聯性 描述
. 表/列名分隔符
:: PostgreSQL 風格型別轉換
[ ] 陣列元素選擇
+ - 一元加、一元減
COLLATE 排序規則選擇
AT AT TIME ZONEAT LOCAL
^ 指數運算
* / % 乘法、除法、模運算
+ - 加法、減法
(任何其他運算子) 所有其他內建和使用者定義的運算子
BETWEEN IN LIKE ILIKE SIMILAR   範圍包含、集合成員、字串匹配
< > = <= >= <>   比較運算子
IS ISNULL NOTNULL   IS TRUEIS FALSEIS NULLIS DISTINCT FROM 等。
NOT 邏輯非
AND 邏輯與
OR 邏輯或

請注意,運算子優先順序規則也適用於具有與上述內建運算子相同名稱的使用者定義運算子。例如,如果您為某個自定義資料型別定義了一個 + 運算子,它的優先順序將與內建的 + 運算子相同,無論它做什麼。

當在 OPERATOR 語法中使用模式限定的運算子名稱時,例如在

SELECT 3 OPERATOR(pg_catalog.+) 4;

中,OPERATOR 構造被視為具有 表 4.2任何其他運算子 的預設優先順序。無論 OPERATOR() 內出現哪個特定運算子,都是如此。

注意

PostgreSQL 9.5 版本之前的版本使用了略有不同的運算子優先順序規則。特別是,<=, >=<> 以前被視為通用運算子;IS 測試以前具有更高的優先順序;NOT BETWEEN 和相關構造的作用不一致,在某些情況下被視為具有 NOT 的優先順序而不是 BETWEEN 的優先順序。這些規則是為了更好地符合 SQL 標準並減少邏輯等效構造處理不一致性帶來的混淆而更改的。在大多數情況下,這些更改不會導致行為變化,或者最多會導致 無此運算子 錯誤,可以透過新增括號來解決。然而,在某些邊緣情況下,查詢可能會在不報告任何解析錯誤的情況下改變行為。

提交更正

如果您在文件中看到任何不正確、與您對特定功能的使用體驗不符或需要進一步澄清的內容,請使用 此表格 來報告文件問題。