排序規則功能允許按列甚至按操作指定資料的排序順序和字元分類行為。這消除了資料庫建立後無法更改 LC_COLLATE
和 LC_CTYPE
設定的限制。
概念上,每個可排序資料型別的表示式都有一個排序規則。(內建的可排序資料型別是 text
、varchar
和 char
。使用者定義的基型別也可以標記為可排序,當然,覆蓋可排序資料型別的 域也是可排序的。)如果表示式是列引用,則表示式的排序規則是該列定義的排序規則。如果表示式是常量,則排序規則是該常量資料型別的預設排序規則。更復雜表示式的排序規則將根據下面描述的其輸入的排序規則派生而來。
表示式的排序規則可以是“預設”排序規則,這意味著為資料庫定義的區域設定。表示式的排序規則也可能是不確定的。在這種情況下,排序操作和其他需要了解排序規則的操作將失敗。
當資料庫系統需要執行排序或字元分類時,它將使用輸入表示式的排序規則。例如,這發生在 ORDER BY
子句以及函式或運算子呼叫(如 <
)時。ORDER BY
子句要應用的排序規則就是排序鍵的排序規則。要應用於函式或運算子呼叫的排序規則將根據下面描述的引數派生而來。除了比較運算子之外,排序規則還會被轉換為大小寫字母的函式(如 lower
、upper
和 initcap
)、模式匹配運算子以及 to_char
和相關函式考慮在內。
對於函式或運算子呼叫,透過檢查引數排序規則派生的排序規則將在執行時用於執行指定的操作。如果函式或運算子呼叫的結果是可排序資料型別,則該排序規則還將在解析時用作函式或運算子表示式的定義排序規則,以防存在需要了解其排序規則的包含表示式。
表示式的“排序規則推導”可以是隱式的或顯式的。這個區別影響了當表示式中出現多個不同的排序規則時,它們是如何組合的。當使用 COLLATE
子句時,會發生顯式排序規則推導;所有其他排序規則推導都是隱式的。當需要組合多個排序規則時(例如在函式呼叫中),將使用以下規則:
如果任何輸入表示式具有顯式排序規則推導,則輸入表示式中的所有顯式推導的排序規則必須相同,否則將引發錯誤。如果存在任何顯式推導的排序規則,則它就是排序規則組合的結果。
否則,所有輸入表示式必須具有相同的隱式排序規則推導或預設排序規則。如果存在任何非預設排序規則,則它就是排序規則組合的結果。否則,結果就是預設排序規則。
如果輸入表示式之間存在衝突的非預設隱式排序規則,則該組合被視為具有不確定的排序規則。除非被呼叫的特定函式需要知道它應該應用的排序規則,否則這不是一個錯誤條件。如果是這樣,將在執行時引發錯誤。
例如,考慮以下表定義
CREATE TABLE test1 ( a text COLLATE "de_DE", b text COLLATE "es_ES", ... );
那麼在
SELECT a < 'foo' FROM test1;
因為表示式組合了隱式推導的排序規則和預設排序規則,所以 <
比較將根據 de_DE
規則執行。但在
SELECT a < ('foo' COLLATE "fr_FR") FROM test1;
因為顯式排序規則推導覆蓋了隱式排序規則,所以比較將使用 fr_FR
規則執行。此外,鑑於
SELECT a < b FROM test1;
解析器無法確定應用哪個排序規則,因為 a
和 b
列具有衝突的隱式排序規則。由於 <
運算子確實需要知道使用哪個排序規則,這將導致錯誤。透過為任一輸入表示式附加顯式排序規則說明符,可以解決此錯誤,例如:
SELECT a < b COLLATE "de_DE" FROM test1;
或等效地
SELECT a COLLATE "de_DE" < b FROM test1;
另一方面,結構上相似的案例
SELECT a || b FROM test1;
不會導致錯誤,因為 ||
運算子不關心排序規則:無論排序規則如何,其結果都是相同的。
分配給函式或運算子組合輸入表示式的排序規則也適用於函式或運算子的結果,如果函式或運算子返回可排序資料型別的話。所以,在
SELECT * FROM test1 ORDER BY a || 'foo';
排序將根據 de_DE
規則進行。但是這個查詢
SELECT * FROM test1 ORDER BY a || b;
導致錯誤,因為即使 ||
運算子不需要知道排序規則,ORDER BY
子句卻需要。和以前一樣,可以透過顯式的排序規則說明符解決衝突:
SELECT * FROM test1 ORDER BY a || b COLLATE "fr_FR";
排序規則是一個 SQL schema 物件,它將 SQL 名稱對映到作業系統中安裝的庫提供的區域設定。排序規則定義有一個“提供者”,它指定哪個庫提供區域設定資料。一個標準的提供者名稱是 libc
,它使用作業系統 C 庫提供的區域設定。這些是作業系統提供的大多數工具使用的區域設定。另一個提供者是 icu
,它使用外部 ICU 庫。只有在構建 PostgreSQL 時配置了 ICU 支援,才能使用 ICU 區域設定。
由 libc
提供的排序規則物件對映到 LC_COLLATE
和 LC_CTYPE
設定的組合,這些設定被 setlocale()
系統庫呼叫接受。(正如名稱所示,排序規則的主要目的是設定 LC_COLLATE
,它控制排序順序。但在實踐中,很少需要 LC_CTYPE
設定與 LC_COLLATE
不同,因此將其收集到一個概念下比建立另一個為每個表示式設定 LC_CTYPE
的基礎設施更方便。)此外,libc
排序規則與字元集編碼相關聯(參見 第 23.3 節)。相同的排序規則名稱可能存在於不同的編碼中。
由 icu
提供的排序規則物件對映到 ICU 庫提供的命名排序器。ICU 不支援單獨的“排序”和“型別”設定,因此它們總是相同的。此外,ICU 排序規則獨立於編碼,因此在資料庫中給定名稱的 ICU 排序規則始終只有一個。
在所有平臺上,都支援以下排序規則:
unicode
此 SQL 標準排序規則使用 Unicode 排序演算法和預設 Unicode 排序元素表進行排序。它在所有編碼中都可用。使用此排序規則需要 ICU 支援,並且如果 PostgreSQL 使用不同版本的 ICU 構建,其行為可能會發生變化。(此排序規則與 ICU 根區域設定的行為相同;參見 und-x-icu
(表示“未定義”)。)
ucs_basic
此 SQL 標準排序規則使用 Unicode 程式碼點值而不是自然語言順序進行排序,並且只有 ASCII 字母“A
”到“Z
”被視為字母。其行為高效且在所有版本中都穩定。僅適用於 UTF8
編碼。(此排序規則與 UTF8
編碼中的 libc 區域設定規範 C
具有相同的行為。)
pg_unicode_fast
此排序規則透過 Unicode 程式碼點值而不是自然語言順序進行排序。對於 lower
、initcap
和 upper
函式,它使用 Unicode 完全大小寫對映。對於模式匹配(包括正則表示式),它使用 Unicode 相容屬性的標準變體。行為在 Postgres 的主要版本內是高效且穩定的。僅適用於 UTF8
編碼。
pg_c_utf8
此排序規則透過 Unicode 程式碼點值而不是自然語言順序進行排序。對於 lower
、initcap
和 upper
函式,它使用 Unicode 簡單大小寫對映。對於模式匹配(包括正則表示式),它使用 Unicode 相容屬性的 POSIX 相容變體。行為在 PostgreSQL 的主要版本內是高效且穩定的。此排序規則僅適用於 UTF8
編碼。
C
(等同於 POSIX
)C 和 POSIX 排序規則基於“傳統 C”行為。它們按位元組值而不是自然語言順序排序,並且只有 ASCII 字母“A
”到“Z
”被視為字母。對於給定的資料庫編碼,其行為在所有版本中都是高效且穩定的,但不同資料庫編碼之間的行為可能有所不同。
default
default 排序規則選擇資料庫建立時指定的區域設定。
根據作業系統支援,可能還有其他排序規則可用。這些附加排序規則的效率和穩定性取決於排序規則提供者、提供者版本和區域設定。
如果作業系統支援在單個程式中使用多個區域設定(newlocale
及相關函式),或者如果配置了 ICU 支援,那麼當資料庫叢集初始化時,initdb
會根據它在初始化時在作業系統中找到的所有區域設定,使用排序規則填充系統目錄 pg_collation
。
要檢查當前可用的區域設定,請使用查詢 SELECT * FROM pg_collation
,或在 psql 中使用命令 \dOS+
。
例如,作業系統可能提供名為 de_DE.utf8
的區域設定。initdb
將為 UTF8
編碼建立一個名為 de_DE.utf8
的排序規則,該排序規則將 LC_COLLATE
和 LC_CTYPE
都設定為 de_DE.utf8
。它還將建立一個名稱字尾為 .utf8 的排序規則。因此,您也可以使用 de_DE
這個名稱使用排序規則,這樣寫起來更方便,並且名稱對編碼的依賴性更小。請注意,儘管如此,初始的排序規則名稱集是平臺依賴的。
libc
提供的預設排序規則集直接對映到作業系統中安裝的區域設定,可以使用命令 locale -a
列出。如果需要一個 LC_COLLATE
和 LC_CTYPE
值不同的 libc
排序規則,或者在資料庫系統初始化後在作業系統中安裝了新的區域設定,則可以使用 CREATE COLLATION 命令建立新的排序規則。也可以使用 pg_import_system_collations()
函式批次匯入新的作業系統區域設定。
在任何特定的資料庫中,只有使用該資料庫編碼的排序規則才是有意義的。pg_collation
中的其他條目將被忽略。因此,即使“de_DE
”這樣的剝離名稱在全域性不唯一,在給定資料庫中也可以認為它是唯一的。建議使用剝離名稱的排序規則,因為如果您決定更改資料庫編碼,需要更改的內容會少一項。但請注意,default
、C
和 POSIX
排序規則可以不考慮資料庫編碼而使用。
PostgreSQL 認為不同的排序規則物件即使具有相同的屬性也是不相容的。因此,例如:
SELECT a COLLATE "C" < b COLLATE "POSIX" FROM test1;
將引發錯誤,即使 C
和 POSIX
排序規則具有相同的行為。因此,不建議混合使用剝離的和非剝離的排序規則名稱。
使用 ICU 時,列舉所有可能的區域設定名稱是不合理的。ICU 使用一種特殊的區域設定命名系統,但命名的區域設定方式比實際存在的不同區域設定要多得多。initdb
使用 ICU API 來提取一組不同的區域設定,以填充排序規則的初始集合。ICU 提供的排序規則在 SQL 環境中建立,名稱採用 BCP 47 語言標籤格式,並附加了“私有使用”擴充套件 -x-icu
,以區別於 libc 排序規則。
以下是一些可能建立的示例排序規則:
某些(較少使用的)編碼不受 ICU 支援。當資料庫編碼是其中之一時,pg_collation
中的 ICU 排序規則條目將被忽略。嘗試使用它們將導致類似於“排序規則“de-x-icu”對於編碼“WIN874”不存在”的錯誤。
如果標準和預定義排序規則不滿足需求,使用者可以使用 SQL 命令 CREATE COLLATION 建立自己的排序規則物件。
與所有預定義物件一樣,標準和預定義排序規則位於 pg_catalog
schema 中。使用者定義的排序規則應在使用者 schema 中建立。這也能確保它們被 pg_dump
儲存。
可以像這樣建立新的 libc 排序規則:
CREATE COLLATION german (provider = libc, locale = 'de_DE');
此命令中 locale
子句可接受的確切值取決於作業系統。在類 Unix 系統上,命令 locale -a
將顯示列表。
由於預定義的 libc 排序規則已經包含了資料庫例項初始化時在作業系統中定義的所有排序規則,因此很少需要手動建立新的排序規則。可能的原因是如果需要不同的命名系統(在這種情況下,請參見 第 23.2.2.3.3 節),或者作業系統已升級以提供新的區域設定定義(在這種情況下,請參見 pg_import_system_collations()
)。
可以像這樣建立 ICU 排序規則:
CREATE COLLATION german (provider = icu, locale = 'de-DE');
ICU 區域設定指定為 BCP 47 語言標籤,但也可以接受大多數 libc 風格的區域設定名稱。如果可能,libc 風格的區域設定名稱將被轉換為語言標籤。
透過在語言標籤中包含排序規則設定,新的 ICU 排序規則可以廣泛地定製排序規則行為。有關詳細資訊和示例,請參閱 第 23.2.3 節。
命令 CREATE COLLATION 也可用於從現有排序規則建立新的排序規則,這有助於在應用程式中使用與作業系統無關的排序規則名稱,建立相容名稱,或者使用 ICU 提供的排序規則作為更易讀的名稱。例如:
CREATE COLLATION german FROM "de_DE"; CREATE COLLATION french FROM "fr-x-icu";
排序規則可以是“確定性”或“非確定性”的。確定性排序規則使用確定性比較,這意味著它僅當字串由相同的位元組序列組成時才認為它們相等。非確定性比較可能會確定字串相等,即使它們由不同的位元組組成。典型情況包括不區分大小寫、不區分重音符號以及比較不同 Unicode 規範形式的字串。由排序規則提供者實際實現這種不區分大小寫的比較;確定性標誌僅決定是否使用位元組序比較來打破平局。有關術語的更多資訊,請參閱 Unicode 技術標準 10。
要建立非確定性排序規則,請在 CREATE COLLATION
中指定屬性 deterministic = false
,例如:
CREATE COLLATION ndcoll (provider = icu, locale = 'und', deterministic = false);
此示例將以非確定性的方式使用標準的 Unicode 排序規則。特別是,這將允許不同規範形式的字串正確比較。更有趣的示例利用了上面解釋的 ICU 自定義功能。例如:
CREATE COLLATION case_insensitive (provider = icu, locale = 'und-u-ks-level2', deterministic = false); CREATE COLLATION ignore_accents (provider = icu, locale = 'und-u-ks-level1-kc-true', deterministic = false);
所有標準和預定義排序規則都是確定性的,所有使用者定義的排序規則預設也是確定性的。雖然非確定性排序規則提供了更“正確”的行為,尤其是在考慮 Unicode 的全部功能及其許多特殊情況時,但它們也有一些缺點。最重要的是,使用它們會導致效能下降。請特別注意,B 樹不能與使用非確定性排序規則的索引進行重複資料刪除。此外,某些操作(例如某些模式匹配操作)對於非確定性排序規則是不可行的。因此,它們應該只在特別需要它們的情況下使用。
為了處理不同 Unicode 規範形式的文字,也可以選擇使用 normalize
和 is normalized
函式/表示式來預處理或檢查字串,而不是使用非確定性排序規則。每種方法都有不同的權衡。
ICU 允許透過定義具有排序設定的新排序規則作為語言標籤的一部分來對排序規則行為進行廣泛控制。這些設定可以修改排序順序以滿足各種需求。例如:
-- ignore differences in accents and case CREATE COLLATION ignore_accent_case (provider = icu, deterministic = false, locale = 'und-u-ks-level1'); SELECT 'Å' = 'A' COLLATE ignore_accent_case; -- true SELECT 'z' = 'Z' COLLATE ignore_accent_case; -- true -- upper case letters sort before lower case. CREATE COLLATION upper_first (provider = icu, locale = 'und-u-kf-upper'); SELECT 'B' < 'b' COLLATE upper_first; -- true -- treat digits numerically and ignore punctuation CREATE COLLATION num_ignore_punct (provider = icu, deterministic = false, locale = 'und-u-ka-shifted-kn'); SELECT 'id-45' < 'id-123' COLLATE num_ignore_punct; -- true SELECT 'w;x*y-z' = 'wxyz' COLLATE num_ignore_punct; -- true
許多可用選項在 第 23.2.3.2 節 中進行了描述,或者有關更多詳細資訊,請參閱 第 23.2.3.5 節。
ICU 中兩個字串(排序規則)的比較是透過一個多級過程確定的,其中文字特徵被分組到“級別”。每個級別的處理由 排序規則設定 控制。較高的級別對應於更精細的文字特徵。
表 23.1 顯示了在給定級別上確定相等性時,哪些文字特徵差異被認為是重要的。Unicode 字元 U+2063
是一個不可見的分隔符,如表中所示,在低於 identic
的所有比較級別上都被忽略。
表 23.1. ICU 排序規則級別
級別 | 描述 | “f” = “f” |
“ab” = U&'a\2063b' |
“x-y” = “x_y” |
“g” = “G” |
“n” = “ñ” |
“y” = “z” |
---|---|---|---|---|---|---|---|
level1 | 基本字元 | true |
true |
true |
true |
true |
false |
level2 | 重音 | true |
true |
true |
true |
false |
false |
level3 | 大小寫/變體 | true |
true |
true |
false |
false |
false |
level4 | 標點符號[a] | true |
true |
false |
false |
false |
false |
identic | 全部 | true |
false |
false |
false |
false |
false |
在每個級別,即使完全不進行規範化,也會執行基本規範化。例如,'á'
可能由程式碼點 U&'\0061\0301'
或單個程式碼點 U&'\00E1'
組成,即使在 identic
級別,這些序列也被視為相等。要將程式碼點表示的任何差異視為不同,請使用 deterministic
設定為 true
建立的排序規則。
CREATE COLLATION level3 (provider = icu, deterministic = false, locale = 'und-u-ka-shifted-ks-level3'); CREATE COLLATION level4 (provider = icu, deterministic = false, locale = 'und-u-ka-shifted-ks-level4'); CREATE COLLATION identic (provider = icu, deterministic = false, locale = 'und-u-ka-shifted-ks-identic'); -- invisible separator ignored at all levels except identic SELECT 'ab' = U&'a\2063b' COLLATE level4; -- true SELECT 'ab' = U&'a\2063b' COLLATE identic; -- false -- punctuation ignored at level3 but not at level 4 SELECT 'x-y' = 'x_y' COLLATE level3; -- true SELECT 'x-y' = 'x_y' COLLATE level4; -- false
表 23.2 顯示了可用的排序規則設定,這些設定可以用作語言標籤的一部分來定製排序規則。
表 23.2. ICU 排序規則設定
鍵 | 值 | 預設 | 描述 |
---|---|---|---|
co |
emoji 、phonebk 、standard 、... |
standard |
排序規則型別。有關其他選項和詳細資訊,請參閱 第 23.2.3.5 節。 |
ka |
noignore 、shifted |
noignore |
如果設定為 shifted ,則某些字元(例如標點符號或空格)在比較時將被忽略。鍵 ks 必須設定為 level3 或更低才能生效。設定鍵 kv 來控制哪些字元類別將被忽略。 |
kb |
true 、false |
false |
級別 2 差異的反向比較。例如,區域設定 und-u-kb 將 'àe' 排序在 'aé' 之前。 |
kc |
true 、false |
false |
將大小寫分隔為“級別 2.5”,介於重音符號和其他級別 3 特徵之間。 如果設定為 |
kf |
upper 、lower 、false |
false |
如果設定為 upper ,則大寫字母排在小寫字母之前。如果設定為 lower ,則小寫字母排在大寫字母之前。如果設定為 false ,則排序取決於區域設定的規則。 |
kn |
true 、false |
false |
如果設定為 true ,則字串中的數字被視為單個數值而不是數字序列。例如,'id-45' 排在 'id-123' 之前。 |
kk |
true 、false |
false |
啟用完全規範化;可能會影響效能。即使設定為 在某些情況下,例如當多個重音符號應用於單個字元時,完全規範化很重要。例如,程式碼點序列 |
kr |
space 、punct 、symbol 、currency 、digit 、script-id |
設定為一個或多個有效值,或任何 BCP 47 重新定義字元類的順序;列表中較早的類中的字元在列表較晚的類中的字元之前排序。例如,值 |
|
ks |
level1 、level2 、level3 、level4 、identic |
level3 |
確定相等性時的敏感性(或“強度”),level1 對差異的敏感性最低,identic 對差異的敏感性最高。有關詳細資訊,請參閱 表 23.1。 |
kv |
space 、punct 、symbol 、currency |
punct |
級別 3 比較時被忽略的字元類別。設定為較晚的值時包括較早的值;例如 symbol 也包括 punct 和 space 在要忽略的字元中。鍵 ka 必須設定為 shifted 並且鍵 ks 必須設定為 level3 或更低才能生效。 |
預設值可能取決於區域設定。上表並非旨在詳盡無遺。有關其他選項和詳細資訊,請參閱 第 23.2.3.5 節。
對於許多排序規則設定,必須將排序規則建立為 deterministic
設定為 false
才能使該設定產生預期效果(參見 第 23.2.2.4 節)。此外,某些設定只有在鍵 ka
設定為 shifted
時才生效(參見 表 23.2)。
CREATE COLLATION "de-u-co-phonebk-x-icu" (provider = icu, locale = 'de-u-co-phonebk');
#德語排序規則,電話簿排序型別
CREATE COLLATION "und-u-co-emoji-x-icu" (provider = icu, locale = 'und-u-co-emoji');
#根排序規則,表情符號排序型別,根據 Unicode 技術標準 #51
CREATE COLLATION latinlast (provider = icu, locale = 'en-u-kr-grek-latn');
#將希臘字母排在拉丁字母之前。(預設是拉丁字母排在希臘字母之前。)
CREATE COLLATION upperfirst (provider = icu, locale = 'en-u-kf-upper');
#將大寫字母排在小寫字母之前。(預設是小寫字母在前。)
CREATE COLLATION special (provider = icu, locale = 'en-u-kf-upper-kr-grek-latn');
#結合了以上兩個選項。
如果上述排序規則設定提供的選項不足,可以使用定製規則更改排序元素順序,其語法在 https://unicode-org.github.io/icu/userguide/collation/customization/ 中有詳細說明。
這個小例子基於根區域設定建立了一個帶有定製規則的排序規則:
CREATE COLLATION custom (provider = icu, locale = 'und', rules = '&V << w <<< W');
透過此規則,“W”字母排在“V”之後排序,但被視為次要差異,類似於重音符號。類似這樣的規則包含在某些語言的區域設定定義中。(當然,如果區域設定定義已包含所需的規則,則無需顯式再次指定。)
這是一個更復雜的例子。以下語句設定了一個名為 ebcdic
的排序規則,其規則按照 EBCDIC 編碼的順序對 US-ASCII 字元進行排序。
CREATE COLLATION ebcdic (provider = icu, locale = 'und', rules = $$ & ' ' < '.' < '<' < '(' < '+' < \| < '&' < '!' < '$' < '*' < ')' < ';' < '-' < '/' < ',' < '%' < '_' < '>' < '?' < '`' < ':' < '#' < '@' < \' < '=' < '"' <*a-r < '~' <*s-z < '^' < '[' < ']' < '{' <*A-I < '}' <*J-R < '\' <*S-Z <*0-9 $$); SELECT c FROM (VALUES ('a'), ('b'), ('A'), ('B'), ('1'), ('2'), ('!'), ('^')) AS x(c) ORDER BY c COLLATE ebcdic; c --- ! a b ^ A B 1 2
本節(第 23.2.3 節)僅是對 ICU 行為和語言標籤的簡要概述。有關技術細節、其他選項和新行為,請參閱以下文件:
如果您在文件中看到任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用 此表單 報告文件問題。