SQL 輸入由一連串的指令組成。一個指令由一連串的符記組成,並以分號(“;”)結尾。輸入串流的結尾也會終止一個指令。哪些符記是有效的取決於特定指令的語法。
符記可以是關鍵字、識別符號、帶引號的識別符號、字面值(或常數),或特殊字元符號。符記通常由空白字元(空格、Tab、換行符)分隔,但如果沒有歧義則不需要分隔(通常只有在特殊字元與其他符記類型相鄰時才會出現這種情況)。
例如,以下是(語法上)有效的 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
才能完成。每個指令的精確語法規則在第六部分中進行了描述。
上面的範例中,諸如 SELECT
、UPDATE
或 VALUES
之類的符記是關鍵字的範例,也就是說,這些詞在 SQL 語言中具有固定的含義。符記 MY_TABLE
和 A
是識別符號的範例。它們識別表、欄或其他資料庫物件的名稱,具體取決於它們在其中使用的指令。因此,它們有時簡稱為“名稱”。關鍵字和識別符號具有相同的詞法結構,這意味著在不知道語言的情況下,無法知道符記是識別符號還是關鍵字。完整的關鍵字列表可以在附錄 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;
引用識別符可以包含任何字元,除了代碼為零的字元。(要包含雙引號,請寫兩個雙引號。)這允許建構原本不可能的表格或欄位名稱,例如包含空格或 & 符號的名稱。長度限制仍然適用。
引用識別符也會使其區分大小寫,而未加引號的名稱始終會摺疊為小寫。例如,識別符 FOO
、foo
和 "foo"
被 PostgreSQL 視為相同,但 "Foo"
和 "FOO"
與這三個不同,且彼此也不同。(在 PostgreSQL 中,未加引號的名稱摺疊為小寫與 SQL 標準不相容,SQL 標準規定未加引號的名稱應摺疊為大寫。因此,根據標準,foo
應等同於 "FOO"
,而不是 "foo"
。如果您想編寫可移植的應用程式,建議您始終引用特定名稱,或永遠不要引用它。)
引用識別符的一種變體允許包含由其代碼點識別的跳脫 Unicode 字元。此變體以 U&
(大寫或小寫 U 後跟 & 符號)緊接在開頭雙引號之前開始,中間沒有任何空格,例如 U&"foo"
。(請注意,這會產生與運算子 &
的歧義。請在運算子周圍使用空格以避免此問題。)在引號內,可以使用跳脫形式指定 Unicode 字元,方法是寫入反斜線後跟四位數的十六進制代碼點編號,或者寫入反斜線後跟一個加號後跟六位數的十六進制代碼點編號。例如,識別符 "data"
可以寫成
U&"d\0061t\+000061"
以下較不平凡的範例用西里爾字母寫出俄語單字「“slon”」(大象)
U&"\0441\043B\043E\043D"
如果需要與反斜線不同的跳脫字元,可以使用字串後的 UESCAPE
子句指定,例如
U&"d!0061t!+000061" UESCAPE '!'
跳脫字元可以是除了十六進制數字、加號、單引號、雙引號或空白字元之外的任何單個字元。請注意,跳脫字元在 UESCAPE
後以單引號而不是雙引號書寫。
若要在識別符中按字面包含跳脫字元,請寫兩次。
4 位數或 6 位數的跳脫形式都可用於指定 UTF-16 代理對,以組成代碼點大於 U+FFFF 的字元,儘管從技術上講,6 位數形式的可用性使這變得不必要。(代理對不會直接儲存,而是組合為單個代碼點。)
如果伺服器編碼不是 UTF-8,則由這些跳脫序列之一識別的 Unicode 代碼點會轉換為實際的伺服器編碼;如果不可能,則會報告錯誤。
在 PostgreSQL 中有三種類型的隱式類型常數:字串、位元字串和數字。常數也可以用顯式類型指定,這可以實現更準確的表示和系統更有效的處理。以下小節將討論這些替代方案。
SQL 中的字串常數是由單引號 ('
) 界定的任意字元序列,例如 'This is a string'
。 若要在字串常數中包含單引號字元,請寫入兩個相鄰的單引號,例如 'Dianne''s horse'
。 請注意,這與雙引號字元 ("
) 不同。
僅由空白字元(至少有一個換行符)分隔的兩個字串常數會被串連,並有效地被視為字串已寫為一個常數。 例如
SELECT 'foo' 'bar';
等同於
SELECT 'foobar';
但
SELECT 'foo' 'bar';
不是有效的語法。(這種稍微奇怪的行為由以下內容指定SQL;PostgreSQL 遵循此標準。)
PostgreSQL 也接受“跳脫”字串常數,這是 SQL 標準的擴展。 跳脫字串常數是透過在開頭單引號前寫字母 E
(大寫或小寫)來指定的,例如 E'foo'
。(跨行繼續跳脫字串常數時,僅在第一個開頭引號前寫 E
。)在跳脫字串中,反斜線字元 (\
) 開始一個類似 C 的反斜線跳脫序列,其中反斜線和後面的字元組合表示一個特殊的位元組值,如表 4.1所示。
表 4.1. 反斜線跳脫序列
反斜線跳脫序列 | 解釋 |
---|---|
\b |
退格 |
\f |
換頁 |
\n |
換行 |
\r |
歸位 |
\t |
製表符 |
\ , \ , \ (o = 0–7) |
八進制位元組值 |
\x , \x (h = 0–9, A–F) |
十六進制位元組值 |
\u , \U (x = 0–9, A–F) |
16 或 32 位元十六進制 Unicode 字元值 |
任何接在反斜線後面的字元都會被視為字面上的字元。因此,要包含一個反斜線字元,請寫兩個反斜線 (\\
)。此外,單引號可以透過寫 \'
來包含在跳脫字串中,除了正常的 ''
方式之外。
您有責任確保您建立的位元組序列,尤其是在使用八進位或十六進位跳脫字元時,在伺服器字元集編碼中構成有效的字元。一個有用的替代方案是使用 Unicode 跳脫字元或替代的 Unicode 跳脫字元語法,詳見第 4.1.2.3 節;然後伺服器會檢查字元轉換是否可行。
如果組態參數 standard_conforming_strings 為 off
,則 PostgreSQL 會在一般字串常數和跳脫字串常數中都識別反斜線跳脫字元。然而,自 PostgreSQL 9.1 起,預設值為 on
,表示只在跳脫字串常數中識別反斜線跳脫字元。此行為更符合標準,但可能會破壞依賴歷史行為的應用程式,在歷史行為中,反斜線跳脫字元總是會被識別。作為一種解決方案,您可以將此參數設定為 off
,但最好是遷移到不使用反斜線跳脫字元。如果您需要使用反斜線跳脫字元來表示特殊字元,請使用 E
寫入字串常數。
除了 standard_conforming_strings
之外,組態參數 escape_string_warning 和 backslash_quote 也會影響字串常數中反斜線的處理方式。
程式碼為零的字元不能出現在字串常數中。
PostgreSQL 也支援另一種類型的字串跳脫字元語法,允許透過程式碼點指定任意 Unicode 字元。Unicode 跳脫字串常數以 U&
(大寫或小寫字母 U 後接連字號)開始,緊接在左引號之前,中間沒有任何空格,例如 U&'foo'
。(請注意,這會造成與運算子 &
的含糊不清。在運算子周圍使用空格來避免此問題。)在引號內,Unicode 字元可以透過寫一個反斜線後接四位數十六進位程式碼點編號,或反斜線後接一個加號後接一個六位數十六進位程式碼點編號,以跳脫字元的形式指定。例如,字串 'data'
可以寫成
U&'d\0061t\+000061'
以下較不平凡的範例用西里爾字母寫出俄語單字「“slon”」(大象)
U&'\0441\043B\043E\043D'
如果需要不同的跳脫字元而不是反斜線,可以使用字串後的 UESCAPE
子句來指定,例如
U&'d!0061t!+000061' UESCAPE '!'
跳脫字元可以是除十六進位數字、加號、單引號、雙引號或空白字元之外的任何單個字元。
若要在字串中按字面意義包含跳脫字元,請將其寫兩次。
4 位數或 6 位數的跳脫形式都可用於指定 UTF-16 代理對,以組成代碼點大於 U+FFFF 的字元,儘管從技術上講,6 位數形式的可用性使這變得不必要。(代理對不會直接儲存,而是組合為單個代碼點。)
如果伺服器編碼不是 UTF-8,則由這些跳脫序列之一識別的 Unicode 代碼點會轉換為實際的伺服器編碼;如果不可能,則會報告錯誤。
此外,字串常數的 Unicode 跳脫字元語法僅在組態參數 standard_conforming_strings 開啟時有效。這是因為否則此語法可能會混淆剖析 SQL 陳述式的用戶端,以至於可能導致 SQL 注入和類似的安全問題。如果參數設定為 off,則此語法將被拒絕並顯示錯誤訊息。
雖然指定字串常數的標準語法通常很方便,但當所需的字串包含許多單引號時,可能難以理解,因為每個單引號都必須加倍。為了允許在這種情況下使用更易讀的查詢,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 標準的一部分,但它通常是比符合標準的單引號語法更方便的編寫複雜字串字面值的方式。當在其他常數內表示字串常數時,它特別有用,這在程序函式定義中經常需要。使用單引號語法,上述範例中的每個反斜線都必須寫成四個反斜線,這將在剖析原始字串常數時減少為兩個反斜線,然後在函式執行期間重新剖析內部字串常數時減少為一個反斜線。
位元字串常數看起來像正規字串常數,在左引號之前緊接一個 B
(大寫或小寫)(沒有中間的空白),例如 B'1001'
。位元字串常數中唯一允許的字元是 0
和 1
。
或者,可以使用前置 X
(大寫或小寫)以十六進位表示法指定位元字串常數,例如 X'1FF'
。此表示法等效於每個十六進位數字具有四個二進位數字的位元字串常數。
位元字串常數的兩種形式都可以像正規字串常數一樣跨行繼續。錢字符號引用不能用於位元字串常數中。
數值常數採用以下一般形式
digits
digits
.[digits
][e[+-]digits
] [digits
].digits
[e[+-]digits
]digits
e[+-]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
類型(32 位元),則最初假定為 integer
類型;否則,如果其值適合 bigint
類型(64 位元),則假定為 bigint
類型;否則,將其視為 numeric
類型。包含小數點和/或指數的常數始終最初假定為 numeric
類型。
數值常數最初分配的資料類型只是類型解析演算法的起點。在大多數情況下,常數會根據上下文自動強制轉換為最合適的類型。 必要時,您可以強制將數值解釋為特定的資料類型,方法是進行類型轉換。 例如,您可以強制將數值視為 real
(float4
) 類型,方法是撰寫:
REAL '1.23' -- string style 1.23::REAL -- PostgreSQL (historical) style
這些實際上只是接下來討論的一般類型轉換表示法的特例。
可以使用以下任何一種表示法輸入任意類型的常數:
type
'string
' 'string
'::type
CAST ( 'string
' AStype
)
字串常數的文字會傳遞給名為 type
的類型的輸入轉換常式。結果是指定類型的常數。如果常數的類型沒有歧義(例如,當它直接賦值給表格欄位時),則可以省略顯式類型轉換,在這種情況下,它會自動強制轉換。
字串常數可以使用常規 SQL 表示法或 dollar-quoting 撰寫。
也可以使用類似函數的語法來指定類型強制轉換:
typename
( 'string
' )
但並非所有類型名稱都可以以這種方式使用;詳情請參閱 第 4.2.9 節。
::
、CAST()
和函數呼叫語法也可以用於指定任意表示式的執行時期類型轉換,如 第 4.2.9 節中所述。為了避免語法上的歧義,
語法只能用於指定簡單文字常數的類型。 對於 type
'string
'
語法的另一個限制是它不適用於陣列類型; 使用 type
'string
'::
或 CAST()
來指定陣列常數的類型。
CAST()
語法符合 SQL 標準。
語法是標準的推廣:SQL 僅為少數資料類型指定此語法,但 PostgreSQL 允許它用於所有類型。 帶有 type
'string
'::
的語法是歷史悠久的 PostgreSQL 用法,函數呼叫語法也是如此。
運算子名稱是由最多 NAMEDATALEN
-1 (預設為 63) 個字元組成的序列,這些字元來自以下清單:
+ - * / < > = ~ ! @ # % ^ & | ` ?
但是,對運算子名稱有一些限制:
--
和 /*
不能出現在運算子名稱的任何位置,因為它們會被視為註解的開頭。
多字元運算子名稱不能以 +
或 -
結尾,除非該名稱還包含以下字元中的至少一個:
~ ! @ # % ^ & | ` ?
例如,@-
是一個允許的運算子名稱,但 *-
不是。此限制允許 PostgreSQL 解析符合 SQL 標準的查詢,而無需在符記之間使用空格。
在使用非 SQL 標準的運算子名稱時,通常需要用空格分隔相鄰的運算子,以避免歧義。 例如,如果您定義了一個名為 @
的前置運算子,則不能撰寫 X*@Y
; 必須撰寫 X* @Y
以確保 PostgreSQL 將其讀取為兩個運算子名稱,而不是一個。
某些非字母數字字元具有特殊含義,這與作為運算子不同。 有關用法的詳細資訊,可以在描述相應語法元素的位置找到。 本節僅旨在建議這些字元的存在並總結其用途。
後接數字的美元符號 ($
) 用於表示函數定義或預備語句主體中的位置參數。 在其他上下文中,美元符號可以是識別碼或 dollar-quoted 字串常數的一部分。
括號 (()
) 具有其通常的含義,用於對表示式進行分組並強制優先順序。 在某些情況下,括號是特定 SQL 命令的固定語法的一部分。
方括號 ([]
) 用於選擇陣列的元素。 有關陣列的更多資訊,請參閱 第 8.15 節。
逗號 (,
) 用於某些語法結構中,以分隔清單的元素。
分號 (;
) 終止 SQL 命令。 它不能出現在命令中的任何位置,除非在字串常數或帶引號的識別碼中。
冒號 (:
) 用於從陣列中選擇「切片」。(參閱 第 8.15 節。)在某些 SQL 方言(例如 Embedded SQL)中,冒號用於作為變數名稱的前綴。
星號 (*
) 在某些上下文中用於表示表格列或複合值的所有欄位。 當它用作彙總函數的參數時,它也具有特殊含義,即彙總不需要任何顯式參數。
句點 (.
) 用於數值常數中,以及分隔綱要、表格和欄位名稱。
註解是以雙破折號開頭並延伸到行尾的字元序列,例如:
-- This is a standard SQL comment
或者,可以使用 C 樣式的區塊註解:
/* multiline comment * with nesting: /* nested block comment */ */
其中註解以 /*
開頭並延伸到匹配的 */
實例。 這些區塊註解會巢狀,如 SQL 標準中所指定,但與 C 不同,因此可以註解掉可能包含現有區塊註解的較大程式碼區塊。
在進一步的語法分析之前,註解會從輸入串流中移除,並有效地被空白字元取代。
表 4.2 顯示了 PostgreSQL 中運算子的優先順序和結合性。大多數運算子具有相同的優先順序並且是左結合的。運算子的優先順序和結合性是硬編碼到剖析器中的。如果您希望以與優先順序規則所暗示的方式不同的方式剖析具有多個運算子的表達式,請添加括號。
表 4.2. 運算子優先順序 (由高至低)
運算子/元素 | 結合性 | 描述 |
---|---|---|
. |
左 | 資料表/欄位名稱分隔符 |
:: |
左 | PostgreSQL 樣式的型別轉換 |
[ ] |
左 | 陣列元素選擇 |
+ - |
右 | 一元正號,一元負號 |
COLLATE |
左 | 定序選擇 |
AT |
左 | AT TIME ZONE , AT LOCAL |
^ |
左 | 指數運算 |
* / % |
左 | 乘法、除法、取模 |
+ - |
左 | 加法、減法 |
(任何其他運算子) | 左 | 所有其他原生和使用者定義的運算子 |
BETWEEN IN LIKE ILIKE SIMILAR |
範圍包含、集合成員、字串匹配 | |
< > = <= >= <> |
比較運算子 | |
IS ISNULL NOTNULL |
IS TRUE , IS FALSE , IS NULL , IS DISTINCT FROM , 等。 |
|
NOT |
右 | 邏輯否定 |
AND |
左 | 邏輯連線 |
OR |
左 | 邏輯析取 |
請注意,運算子優先順序規則也適用於具有與上面提到的內建運算子相同名稱的使用者定義運算子。例如,如果您為某些自訂資料型別定義一個 「+」 運算子,無論您的運算子做什麼,它都將具有與內建 「+」 運算子相同的優先順序。
當schema限定的運算子名稱用於OPERATOR
語法中時,例如在
SELECT 3 OPERATOR(pg_catalog.+) 4;
OPERATOR
結構會被認為具有表 4.2中“任何其他運算子”的預設優先順序。無論哪個特定運算子出現在OPERATOR()
中,這都是正確的。
9.5 之前的 PostgreSQL 版本使用了稍微不同的運算子優先順序規則。特別是,<=
>=
和 <>
過去被視為通用運算子;IS
測試過去具有更高的優先順序;並且 NOT BETWEEN
和相關結構的行為不一致,在某些情況下被認為具有 NOT
的優先順序,而不是 BETWEEN
。 這些規則的變更旨在更好地符合 SQL 標準,並減少因邏輯上等效的結構處理不一致而造成的混淆。 在大多數情況下,這些更改不會導致行為上的改變,或者可能導致 “沒有此運算子” 錯誤,可以透過新增括號來解決。 但是,在某些特殊情況下,查詢可能會在沒有報告任何剖析錯誤的情況下變更行為。
如果您在文件中看到任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的內容,請使用此表單來報告文件問題。