# 文本类型

> 存储和比较文本，测量字符长度，并理解填充和排序规则。

---

LLMS 索引： [llms.txt](/llms.txt)

---

PostgreSQL 有三种字符类型：`text`（无界）、`varchar(n)`（可变长度，最多 `n` 个字符）和 `char(n)`（固定 `n` 个字符，以空格填充）。对于几乎所有使用场景，`text` 都是正确的选择。PostgreSQL 的 `text` 和 `varchar` 在*性能特征*上完全相同——与 MySQL 不同，除非希望让数据库强制执行最大长度，否则限制长度没有任何好处。

## 本章要点 {#learn}

- 三种文本类型，以及各自适用的场景
- 为什么 `text` 是 PostgreSQL 中的默认选择
- 长度函数：`length`、`char_length`、`octet_length`
- 排序规则基础——文本如何排序和比较
- 编码：PostgreSQL 使用数据库的编码存储文本（通常是 UTF-8）

## 示例 {#example}

```sql {num="12.1" caption="文本类型"}
-- text: unbounded, recommended default
SELECT 'hello'::text AS t, length('hello'::text) AS chars;

-- varchar(n): same as text but enforces max length
SELECT 'hi'::varchar(10) AS v, length('hi'::varchar(10)) AS chars;

-- char(n): fixed length, padded with spaces
SELECT 'ab'::char(5) AS c, length('ab'::char(5)) AS chars, '|' || 'ab'::char(5) || '|' AS padded;

-- char_length vs octet_length on multibyte text
SELECT char_length('café') AS chars, octet_length('café') AS bytes;

-- A taste of collation: byte-order sort
SELECT * FROM (VALUES ('apple'), ('Banana'), ('cherry')) AS t(name)
ORDER BY name COLLATE "C";
```

`text` 是最常用的文本类型。它可以存储任意长度的字符串，也是大多数应用列应该使用的类型。在内部，PostgreSQL 以相同方式存储 `text` 和 `varchar`，对大值使用 TOAST（超长属性存储技术），从而让主表保持紧凑。

`varchar(n)` 就是在 `text` 上增加了长度检查。只有在确实有理由限制长度时才使用它（例如需要与某个要求使用这种类型的系统集成）。不带长度的 `varchar` 与 `text` 完全相同。

`char(n)` 是历史遗留的定长类型。它在存储时用空格将值填充到 `n` 的长度，并在某些操作中去掉这些空格，因此会带来意外。除非有非常具体的理由（例如需要与要求定长编码的系统对接），否则应避免使用 `char(n)`。

## 运行示例 {#run}

运行方式：

```text
$ psql -f source/text-types.sql postgres
   t   | chars
-------+-------
 hello |     5
(1 row)

 v  | chars
----+-------
 hi |     2
(1 row)

   c   | chars |  padded
-------+-------+----------
 ab    |     2 | |ab|
(1 row)
 ...
```

## 常见陷阱 {#pitfalls}

- 出于习惯选择 `varchar(255)`：在 PostgreSQL 中它没有实际用处。请使用 `text`。如果应用确实需要限制长度，就在应用中或通过 `CHECK` 约束来强制执行。
- `char(n)` 的填充会悄悄改变你的值。`'foo'::char(10)` 会存储为 `'foo       '`。
- 多字节字符：`length('café')` 返回 4（字符数），而 `octet_length` 返回 5（UTF-8 中的字节数）。根据你要回答的问题选择合适的函数。
- 排序时的比较取决于数据库的 `LC_COLLATE`。要按字节顺序排序（通常更快，也更可预测），请使用 `COLLATE "C"`。

> [!TIP] 提示
> 对于不区分大小写的文本列，可以考虑使用 `citext` 扩展（`CREATE EXTENSION citext`）——它可以让列级别的 `=` 和 `LIKE` 比较不区分大小写，这样查询就不必到处调用 `LOWER()`。

> [!NOTE] 动手练习
> 比较长度：`SELECT length('x'::text), length('x'::char(3));`。两者长度都是 1：`length(character)` 会忽略末尾填充的空格。使用 `octet_length('x'::char(3))` 查看存储的三个字节。然后尝试 `SELECT 'foo   '::char(6) = 'foo'::char(3);`——结果是 `true`，因为 `char` 比较会忽略末尾空格。

## 下载 {#downloads}

SQL 文件：[text-types.sql](/examples/source/text-types.sql) · [全部示例文件](/examples/examples.zip) · [准备工作](/#prerequisites)
