char 和 varchar (Transact-SQL)

适用于:SQL Server Azure SQL 数据库 Azure SQL 托管实例 Azure Synapse Analytics Analytics Platform System (PDW) Microsoft Fabric 中的 SQL 终结点 Microsoft Fabric 中的仓库 Microsoft Fabric SQL 数据库

字符数据类型 char(大小固定)或 varchar(大小可变)。 从 SQL Server 2019 (15.x)开始,当使用 UTF-8 启用排序规则时,这些数据类型存储 Unicode 字符数据的完整范围,并使用 UTF-8 字符编码。 若指定了非 UTF-8 排序规则,则这些数据类型仅会存储该排序规则的相应代码页支持的字符子集。

参数

char [ ( n ) ]

固定大小字符串数据。 n 用于定义字符串大小(以字节为单位),并且它必须为 1 到 8,000 之间的值。 对于单字节编码字符集(如 Latin),存储大小为 n 个字节,并且可存储的字符数也为 n。 对于多字节编码字符集,存储大小仍 为 n 个字节,但可以存储的字符数可能小于 nchar 的 ISO 同义词是 character。 有关字符集的详细信息,请参阅单字节和多字节字符集

varchar [ ( n | max ) ]

可变大小字符串数据。 使用 n 定义字符串大小(以字节为单位),可以是介于 1 和 8,000 之间的值;或使用 max 指明列约束大小上限为最大存储 2^31-1 个字节 (2 GB)。 对于单字节编码字符集(如 Latin),存储大小为 n + 2 个字节,并且可存储的字符数也为 n。 对于多字节编码字符集,存储大小仍然是 n 个字节 + 2 个字节,但可以存储的字符数可能小于 nvarchar 的 ISO 同义词是 char varyingcharacter varying。 有关字符集的详细信息,请参阅单字节和多字节字符集

备注

一个常见的误解是,认为在 char(n)varchar(n) 中,n 定义字符数。 但在 char(n)varchar(n) 中,n 定义字符串的长度(以字节为单位)(0-8,000)。 n 不会定义可存储的字符数。 此概念类似于 nchar 和 nvarchar 的定义

出现此误解的原因是,在使用单字节编码时,char 和 varchar 的存储大小为 数字 个字节,并且字符数也为 n。 但是,对于多字节编码(如 UTF-8),更高的 Unicode 范围 (128-1,114,111) 会导致一个字符使用两个或更多字节。 例如,在定义为 char (10) 的列中,数据库引擎可以存储使用单字节编码(Unicode 范围 0-127)的 10 个字符,但在使用多字节编码(Unicode 范围 128-1,114,111)时,将少于 10 个字符。 有关 Unicode 存储和字符范围的详细信息,请参阅 UTF-8 与 UTF-16 之间的存储差异

如果没有在数据定义或变量声明语句中指定 n,则默认长度为 1。 如果在使用 CASTCONVERT 函数时未指定 n,则默认长度为 30。

为使用 charvarchar 的对象分配的是默认数据库排序规则,但可使用 COLLATE 子句分配特定的排序规则。 该排序规则控制用于存储字符数据的代码页。

SQL Server 中的多字节编码包括:

  • 使用代码页 936 及 950(中文)、932(日文)或 949(韩文)的某些东亚语言的双字节字符集 (DBCS)。

  • 使用代码页 65001 的 UTF-8。

    适用于:SQL Server 2019 (15.x) 及更高版本。

若你拥有支持多种语言的站点:

  • 从 SQL Server 2019 (15.x) 开始,考虑使用已启用 UTF-8 的排序规则,以支持 Unicode 并最大程度地减少字符转换问题。
  • 若使用以前版本的 SQL Server 数据库引擎,请考虑使用 Unicode ncharnvarchar 数据类型,以最大程度地减少字符转换问题。

若使用 charvarchar,则建议:

  • 如果列数据项的大小一致,则使用 char
  • 如果列数据项的大小差异相当大,则使用 varchar
  • 如果列数据项大小相差很大,而且字符串长度可能超过 8,000 字节,请使用 varchar(max)

OFF如果在SET ANSI_PADDING任一时间执行或ALTER TABLECREATE TABLE执行,则定义为 NULL varchar字符列。

警告

每个非 null varchar(max)nvarchar(max) 列都需要 24 个字节的附加固定分配,这将在执行排序操作期间计入 8,060 字节行限制。 这样一来,可能会为非 null varchar(max)nvarchar(max)(可在表格中进行创建)列数创建隐式限制。

在以下情况下不提供特殊错误:创建表格(最大行大小超过允许的最大 8,060 字节时出现的一般警告除外)时,或插入数据时。 这一较大的行大小可能会导致在执行某些正常操作(例如聚集索引键更新或完整列集排序)期间出现错误(例如错误 512),这些错误只会在执行操作时发生。

转换字符数据

如果将字符表达式转换为不同大小的字符数据类型,则对于新数据类型而言过长的值将被截断。 出于从字符表达式转换的目的将 uniqueidentifier 类型视为字符类型,因此,在转换到字符类型时要遵循截断规则。 请参阅示例部分。

如果将某个字符表达式转换为不同数据类型或大小的字符表达式(例如从 char(5) 转换为 varchar(5) 或从 char(20) 转换为 char(15))),则输入值的排序规则会被分配给经过转换的值。 如果将非字符表达式转换为字符数据类型,则当前数据库的默认排序规则会被分配给经过转换的值。 在任意一种情况下,都可以使用 COLLATE 子句分配特定的排序规则。

注意

charvarchar 数据类型支持代码页转换,但是 text 数据类型不支持。 与 SQL Server 的早期版本一样,将不报告代码页转换期间的数据丢失。

要转换为近似 numeric 数据类型的字符表达式可以包括可选的指数表示法。 此表示法为一个小写的 e 或一个大写的 E 后跟可选的加号 (+) 或减号 (-),再后跟一个数字。

要转换为精确 numeric 数据类型的字符表达式必须包含数字、小数点和可选的加号 (+) 或减号 (-)。 将忽略前导空格。 不允许在字符串中使用逗号分隔符,例如 123,456.00 中的千位分隔符。

要转换为 moneysmallmoney 数据类型的字符表达式还可以包含可选的小数点和美元符号 ($)。 可以使用逗号分隔符(如在 $123,456.00 中)。

空字符串转换为 int 时,其值将变为 0。 当空字符串转换为日期时,其值将变为 日期 - 即 1900-01-01

示例

A. 在变量声明中使用时,显示 n 的默认值

以下示例演示在变量声明中使用的 charvarchar 数据类型的默认值 n 为 1。

DECLARE @myVariable AS VARCHAR = 'abc';
DECLARE @myNextVariable AS CHAR = 'abc';

--The following query returns 1
SELECT DATALENGTH(@myVariable), DATALENGTH(@myNextVariable);
GO

B. 在 CAST 和 CONVERT 中使用 varchar 时,显示 n 的默认值

以下示例显示在 CASTCONVERT 函数中使用 charvarchar 数据类型时,n 的默认值为 30。

DECLARE @myVariable AS VARCHAR(40);
SET @myVariable = 'This string is longer than thirty characters';

SELECT CAST(@myVariable AS VARCHAR);
SELECT DATALENGTH(CAST(@myVariable AS VARCHAR)) AS 'VarcharDefaultLength';
SELECT CONVERT(CHAR, @myVariable);
SELECT DATALENGTH(CONVERT(CHAR, @myVariable)) AS 'VarcharDefaultLength';

C. 转换数据以便于显示

以下示例将两列转换为字符类型并应用一种样式,该样式将特定格式应用于所显示的数据。 money 类型转换为字符数据并应用样式 1,这会对小数点左侧的每三个数字和对小数点右侧的每两个数字加一个逗号来显示值。 datetime 类型转换为字符数据并应用样式 3,这会以 dd/mm/yy 格式来显示数据。 在 WHERE 子句中,money 类型强制转换为字符类型,以执行字符串比较操作。

USE AdventureWorks2022;
GO

SELECT BusinessEntityID,
    SalesYTD,
    CONVERT(VARCHAR(12), SalesYTD, 1) AS MoneyDisplayStyle1,
    GETDATE() AS CurrentDate,
    CONVERT(VARCHAR(12), GETDATE(), 3) AS DateDisplayStyle3
FROM Sales.SalesPerson
WHERE CAST(SalesYTD AS VARCHAR(20)) LIKE '1%';

结果集如下。

BusinessEntityID SalesYTD              DisplayFormat CurrentDate             DisplayDateFormat
---------------- --------------------- ------------- ----------------------- -----------------
278              1453719.4653          1,453,719.47  2011-05-07 14:29:01.193 07/05/11
280              1352577.1325          1,352,577.13  2011-05-07 14:29:01.193 07/05/11
283              1573012.9383          1,573,012.94  2011-05-07 14:29:01.193 07/05/11
284              1576562.1966          1,576,562.20  2011-05-07 14:29:01.193 07/05/11
285              172524.4512           172,524.45    2011-05-07 14:29:01.193 07/05/11
286              1421810.9242          1,421,810.92  2011-05-07 14:29:01.193 07/05/11
288              1827066.7118          1,827,066.71  2011-05-07 14:29:01.193 07/05/11

D. 转换 uniqueidentifier 数据

以下示例将 uniqueidentifier 值转换为 char 数据类型。

DECLARE @myid UNIQUEIDENTIFIER = NEWID();
SELECT CONVERT(CHAR(255), @myid) AS 'char';

以下示例演示在值过长而无法转换数据类型时如何截断数据。 因为 uniqueidentifier 类型限制为 36 个字符,所以,将截断超过该长度的字符。

DECLARE @ID NVARCHAR(MAX) = N'0E984725-C51C-4BF4-9960-E1C80E27ABA0wrong';
SELECT @ID, CONVERT(UNIQUEIDENTIFIER, @ID) AS TruncatedValue;

结果集如下。

String                                     TruncatedValue
------------------------------------------ ------------------------------------
0E984725-C51C-4BF4-9960-E1C80E27ABA0wrong  0E984725-C51C-4BF4-9960-E1C80E27ABA0