

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 定序限制與行為差異
<a name="collation.limitations"></a>

Babelfish 使用 ICU 程式庫來支援定序。PostgreSQL 以特定版本的 ICU 建置，最多只能符合定序的一個版本。不同版本的變化不可避免，就像語言隨著時間演變，也會發生微小的變化。您下列清單中可以找到 Babelfish 定序的已知限制和行為變化：
+ **索引與定序類型相依性** – 依據 International Components for Unicode (ICU) 定序程式庫 (Babelfish 使用的程式庫) 的使用者定義類型索引，不會在程式庫版本變更時失效。
+ **COLLATIONPROPERTY 函數** – 針對支援的 Babelfish BBF 定序實作定序屬性。如需更多資訊，請參閱[Babelfish supported collations table](babelfish-collations.md#bfish-collations-table)。
+ **Unicode 排序規則差異** – SQL Server 的 SQL 定序將 Unicode 編碼的資料 (`nchar` 和 `nvarchar`) 排序的方式不同於非 Unicode 編碼的資料 (`char` 和 `varchar`)。Babelfish 資料庫一律為 UTF-8 編碼，且不論資料類型為何，一律以一致的方式套用 Unicode 排序規則，因此 `char` 或 `varchar` 的排序順序與 `nchar` 或 `nvarchar` 的相同。
+ **第二級相等定序與排序行為** – 預設 ICU Unicode 第二級相等 (`CI_AS`) 定序將標點符號和其他非英數字元排在數值字元前面，並將數值字元排在字母字元前面。但是，標點符號和其他特殊字元的順序不同。
+ **Tertiary collations, workaround for ORDER BY** – SQL 定序 (例如 `SQL_Latin1_General_Pref_CP1_CI_AS`) 支援 `TERTIARY_WEIGHTS` 函數，且能夠將 `CI_AS` 定序中視為同等的字串排序為大寫優先：`ABC`、`ABc`、`AbC`、`Abc`、`aBC`、`aBc`、`abC`，最後是 `abc`。因此，`DENSE_RANK OVER (ORDER BY column)` 分析函數將這些字串評估為相同等級，但在分割區內以大寫優先來排序。

  在 Babelfish 中，您可以在指定第三級 `CS_AS` 定序的 `ORDER BY` 子句中，新增 `COLLATE` 子句來指定 `@colCaseFirst=upper`，以獲得類似的結果。不過，`colCaseFirst` 修飾詞僅適用於第三級相等的字串 (而不是第二級相等，例如 `CI_AS` 定序)。因此，您無法使用單一 ICU 定序來模擬第三級 SQL 定序。

  為了解決這種情況，建議您將使用 `SQL_Latin1_General_Pref_CP1_CI_AS` 定序的應用程式修改成優先使用 `BBF_SQL_Latin1_General_CP1_CI_AS` 定序。然後將 `COLLATE BBF_SQL_Latin1_General_Pref_CP1_CS_AS` 新增至此資料欄的任何 `ORDER BY` 子句。
+ **字元擴充** – 字元擴充將單一字元視為等同於主要層級的一連串字元。SQL Server 的預設 `CI_AS` 定序支援字元擴展。ICU 定序僅支援不區分重音定序的字元擴展。

  需要字元擴充時，請使用 `AI` 定序來做比較。不過，LIKE 運算子目前不支援這種定序。
+ **char 與 varchar 編碼** – 當 SQL 定序用於 `char` 或 `varchar` 資料類型時，ASCII 127 之前的字元由該 SQL 定序的特定字碼頁決定排序順序。使用 SQL 定序時，宣告為 `char` 或 `varchar` 的字串與宣告為 `nchar` 或 `nvarchar` 的字串，可能以不同方式排序。

  PostgreSQL 使用資料庫編碼將所有字串編碼，因此會將所有字元轉換為 UTF-8，並根據 Unicode 規則來排序。

  因為 SQL 定序使用 Unicode 規則來排序 nchar 和 nvarchar 資料類型，所以 Babelfish 使用 UTF-8 將伺服器上的所有字串編碼。Babelfish 使用 Unicode 規則來排序 nchar 和 nvarchar 字串的方式，同於排序 char 和 varchar。
+ **補增字元** – SQL Server 函數 `NCHAR`、`UNICODE` 及 `LEN` 支援 Unicode Basic Multilingual Plane (BMP) 以外字碼指標的字元。反之，非 SC 定序使用代理配對字元來處理增補字元。對於 Unicode 資料類型，SQL Server 可以使用 UCS-2 來表示最多 65,535 個字元，或者，如果使用增補字元，則表示完整的 Unicode 範圍 (1,114,114 個字元)。
+ **區分假名 (KS) 定序** –「區分假名」(KS) 定序會將 `Hiragana` 和 `Katakana` 日文假名字元視為不同。ICU 支援日文定序標準 `JIS X 4061`。現在已棄用的 `colhiraganaQ [on | off]` 地區設定修飾詞可能有同於 KS 定序的功能。不過，Babelfish 目前不支援與 SQL Server 同名的 KS 定序。
+ **區分寬度 (WS) 定序** – 將單一位元組字元 (半形) 和以雙位元組字元 (全形) 表示的同一個字元視為不同時，定序就稱為*區分寬度 (WS)*。不過，Babelfish 目前不支援與 SQL Server 同名的 WS 定序。
+ **區分變化選擇器 (VSS) 定序** – 區分變化選擇器 (VSS) 定序會區分日文定序 `Japanese_Bushu_Kakusu_140` 和 `Japanese_XJIS_140` 中的表意變化選擇器。變化序列由一個基本字元加上一個額外的變化選擇器組成。如果您未選取 `_VSS` 選項，則做比較時不會考慮變化選擇器。

  Babelfish 目前不支援 VSS 定序。
+ **BIN 與 BIN2 定序** – BIN2 定序根據字碼指標順序來排序字元。UTF-8 的逐位元組二進制順序保留 Unicode 字碼指標順序，因此這也可能是表現最佳的定序。如果 Unicode 代碼指標順序適用於應用程式，請考慮使用 BIN2 定序。不過，使用 BIN2 定序可能會導致資料在用戶端以超出文化預期的順序顯示。隨著時間經過，Unicode 中也增加對小寫字元的新映射，因此 `LOWER` 函數在不同版本的 ICU 上可能有以不同方式運作。這是較常見定序版本控制問題的特殊情況，而不是 BIN2 定序所獨有。

  Babelfish 隨著 Babelfish 發佈而提供 `BBF_Latin1_General_BIN2` 定序，以依照 Unicode 代碼指標順序來排序。在 BIN 定序中，只有第一個字元排序為 wchar。剩餘的字元逐位元組來排序，實際上是依照符合其編碼的代碼指標順序。這種作法未遵循 Unicode 定序，Babelfish 並不支援。
+ **非確定性定序和 CHARINDEX 限制** – 對於早於第 2.1.0 版的 Babelfish 版本，您無法將 CHARINDEX 與非確定性定序搭配使用。預設情況下，Babelfish 使用不區分大小寫 (非確定性) 定序。對舊版 Babelfish 使用 CHARINDEX 會造成下列執行時間錯誤：

  ```
  nondeterministic collations are not supported for substring searches
  ```
**注意**  
此限制和解決方法僅適用於 Babelfish 1.x 版 (Aurora PostgreSQL 13.x 版)。Babelfish 2.1.0 及更新版本沒有此問題。

  您可以透過以下其中一種方法解決此問題：
  + 將表達式明確轉換為區分大小寫的定序，並套用 LOUP 或 UPER 將這兩個參數進行大小寫折疊 (case-fold)。例如，`SELECT charindex('x', a) FROM t1` 會變成下列：

    ```
    SELECT charindex(LOWER('x'), LOWER(a COLLATE sql_latin1_general_cp1_cs_as)) FROM t1
    ```
  + 建立一個 SQL 函數 f\$1charindex，並將 CHARINDEX 呼叫替換為對以下函數的呼叫：

    ```
    CREATE function f_charindex(@s1 varchar(max), @s2 varchar(max)) RETURNS int
    AS
    BEGIN
    declare @i int = 1
    WHILE len(@s2) >= len(@s1)
    BEGIN
      if LOWER(@s1) = LOWER(substring(@s2,1,len(@s1))) return @i
      set @i += 1
      set @s2 = substring(@s2,2,999999999)
    END
    return 0
    END
    go
    ```