支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:開發中
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4

F.9. citext — 不區分大小寫的字串類型 #

citext 模組提供了一個不區分大小寫的字串類型,citext。 本質上,它在比較值時在內部呼叫 lower。 除此之外,它的行為幾乎與 text 完全相同。

提示

考慮使用非決定性的定序(請參閱第 23.2.2.4 節)而不是此模組。 它們可用於不區分大小寫的比較、不區分重音符號的比較和其他組合,並且它們可以正確處理更多 Unicode 特殊情況。

此模組被視為受信任的,也就是說,具有目前資料庫的 CREATE 權限的非超級使用者可以安裝它。

F.9.1. 基本原理 #

PostgreSQL 中執行不區分大小寫比對的標準方法是在比較值時使用 lower 函式,例如

SELECT * FROM tab WHERE lower(col) = LOWER(?);

這在合理程度上有效,但存在一些缺點

  • 它使您的 SQL 陳述式冗長,並且您必須始終記住對欄位和查詢值都使用 lower

  • 它不會使用索引,除非您使用 lower 建立函數索引。

  • 如果您將欄位宣告為 UNIQUEPRIMARY KEY,則隱式產生的索引會區分大小寫。 因此,它對不區分大小寫的搜尋沒有用處,並且不會以不區分大小寫的方式強制唯一性。

citext 資料類型允許您消除 SQL 查詢中對 lower 的呼叫,並允許主鍵不區分大小寫。citext 具有地區設定感知能力,就像 text 一樣,這表示大寫和小寫字元的比對取決於資料庫的 LC_CTYPE 設定規則。 同樣,此行為與在查詢中使用 lower 相同。 但是由於它是由資料類型透明地完成的,因此您不必記住在查詢中執行任何特殊操作。

F.9.2. 如何使用 #

這是一個簡單的使用範例

CREATE TABLE users (
    nick CITEXT PRIMARY KEY,
    pass TEXT   NOT NULL
);

INSERT INTO users VALUES ( 'larry',  sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Tom',    sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Damian', sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'NEAL',   sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Bjørn',  sha256(random()::text::bytea) );

SELECT * FROM users WHERE nick = 'Larry';

SELECT 陳述式將傳回一個元組,即使 nick 欄位設定為 larry 且查詢是針對 Larry

F.9.3. 字串比較行為 #

citext 透過將每個字串轉換為小寫(如同呼叫 lower 一樣),然後正常比較結果來執行比較。 因此,例如,如果 lower 會為它們產生相同的結果,則兩個字串被視為相等。

為了盡可能地模擬不區分大小寫的定序,存在許多字串處理運算符和函式的 citext 特定版本。 因此,例如,正規表示式運算符 ~~* 在應用於 citext 時會表現出相同的行為:它們都以不區分大小寫的方式比對。 !~!~*,以及 LIKE 運算符 ~~~~*,以及 !~~!~~* 也是如此。 如果您想區分大小寫地比對,則可以將運算符的引數轉換為 text

同樣,如果下列所有函式的引數是 citext,則它們會以不區分大小寫的方式執行比對

  • regexp_match()

  • regexp_matches()

  • regexp_replace()

  • regexp_split_to_array()

  • regexp_split_to_table()

  • replace()

  • split_part()

  • strpos()

  • translate()

對於正規表示式函式,如果您想區分大小寫地比對,則可以指定c旗標來強制區分大小寫的比對。 否則,如果您想要區分大小寫的行為,則必須在使用這些函式之一之前轉換為 text

F.9.4. 限制 #

  • citext 的大小寫轉換行為取決於資料庫的 LC_CTYPE 設定。 因此,它如何比較值是在建立資料庫時決定的。 就 Unicode 標準定義的術語而言,它並非真正不區分大小寫。 實際上,這表示只要您對定序感到滿意,您就應該對 citext 的比較感到滿意。 但是,如果您的資料庫中儲存了不同語言的資料,則如果定序適用於另一種語言,一種語言的使用者可能會發現他們的查詢結果不如預期。

  • PostgreSQL 9.1 開始,您可以將 COLLATE 規範附加到 citext 欄位或資料值。 目前,citext 運算符在比較大小寫摺疊字串時將採用非預設 COLLATE 規範,但初始摺疊為小寫始終根據資料庫的 LC_CTYPE 設定完成(也就是說,如同給定 COLLATE "default" 一樣)。 這可能會在未來的版本中更改,以便兩個步驟都遵循輸入的 COLLATE 規範。

  • 由於運算子函式和 B-樹比較函式必須複製資料並將其轉換為小寫以進行比較,因此 citext 不如 text 有效率。此外,只有 text 支援 B-樹去重(deduplication)。然而,citext 比使用 lower 進行不區分大小寫的比對稍微有效率一些。

  • 如果您需要在某些情況下區分大小寫比較資料,而在其他情況下不區分大小寫,那麼 citext 的幫助不大。標準的解決方案是使用 text 類型,並在需要進行不區分大小寫的比較時手動使用 lower 函式;如果只需要偶爾進行不區分大小寫的比較,這樣做是可以的。如果您大部分時間需要不區分大小寫的行為,而很少需要區分大小寫的行為,請考慮將資料儲存為 citext,並在需要區分大小寫的比較時,將該欄位明確轉換為 text。無論哪種情況,如果您希望兩種搜尋都很快,您都需要兩個索引。

  • 包含 citext 運算子的綱要(schema)必須在目前的 search_path 中(通常是 public);如果不是,則會改為調用正常的區分大小寫的 text 運算子。

  • 對於某些 Unicode 特殊情況,例如一個大寫字母有兩個小寫字母等價物的情況,將字串轉換為小寫進行比較的方法無法正確處理。因此,Unicode 區分了大小寫映射(case mapping)大小寫折疊(case folding)。請使用非決定性的排序規則(collation)而不是 citext 來正確處理這種情況。

F.9.5. 作者 #

David E. Wheeler

靈感來自 Donald Fraser 的原始 citext 模組。

提交更正

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