sql-server - varchar 中用于 Unicode 字符的字节数
问题描述
一个常见的误解是认为 CHAR(n) 和 VARCHAR(n) 中的 n 定义了字符数。但在 CHAR(n) 和 VARCHAR(n) 中,n 定义了以字节为单位的字符串长度 (0-8,000)。n 从不定义可以存储的字符数
根据微软的这个声明,我假设 n 是字符串的数据长度,当我们将 unicode 字符存储在 中时varchar
,单个字符应该占用 2 个字节。但是,当我尝试使用如下示例时,我看到varchar
数据占用 1 个字节而不是 2 个字节。
declare @varchar varchar(6), @nvarchar nvarchar(6)
set @varchar = 'Ø'
select @varchar as VarcharString, len(@varchar) as VarcharStringLength, DATALENGTH(@varchar) as VarcharStringDataLength
有人可以解释其背后的原因吗?
解决方案
抽出时间来测试我的第一个答案的假设:
- 创建支持 UTF8 的数据库
CREATE DATABASE [test-sc] COLLATE Latin1_General_100_CI_AI_KS_SC_UTF8
- 创建具有各种 N/VARCHAR 列的表
CREATE TABLE [dbo].[UTF8Test](
[Id] [int] IDENTITY(1,1) NOT NULL,
[VarcharText] [varchar](50) COLLATE Latin1_General_100_CI_AI NULL,
[VarcharTextSC] [varchar](50) COLLATE Latin1_General_100_CI_AI_KS_SC NULL,
[VarcharUTF8] [varchar](50) COLLATE Latin1_General_100_CI_AI_KS_SC_UTF8 NULL,
[NVarcharText] [nvarchar](50) COLLATE Latin1_General_100_CI_AI_KS NULL,
[NVarcharTextSC] [nvarchar](50) COLLATE Latin1_General_100_CI_AI_KS_SC NULL,
[NVarcharUTF8] [nvarchar](50) COLLATE Latin1_General_100_CI_AI_KS_SC_UTF8 NULL)
- 插入来自各种 Unicode 范围的测试数据
INSERT INTO [dbo].[UTF8Test] ([VarcharText],[VarcharTextSC],[VarcharUTF8],[NVarcharText],[NVarcharTextSC],[NVarcharUTF8])
VALUES ('a','a','a','a','a','a')
INSERT INTO [dbo].[UTF8Test] ([VarcharText],[VarcharTextSC],[VarcharUTF8],[NVarcharText],[NVarcharTextSC],[NVarcharUTF8])
VALUES ('ö','ö','ö',N'ö',N'ö',N'ö')
-- U+56D7
INSERT INTO [dbo].[UTF8Test] ([VarcharText],[VarcharTextSC],[VarcharUTF8],[NVarcharText],[NVarcharTextSC],[NVarcharUTF8])
VALUES (N'囗',N'囗',N'囗',N'囗',N'囗',N'囗')
-- U+2000B
INSERT INTO [dbo].[UTF8Test] ([VarcharText],[VarcharTextSC],[VarcharUTF8],[NVarcharText],[NVarcharTextSC],[NVarcharUTF8])
VALUES (N'',N'',N'',N'',N'',N'')
- 选择长度
SELECT TOP (1000) [Id]
,[VarcharText]
,[VarcharTextSC]
,[VarcharUTF8]
,[NVarcharText]
,[NVarcharTextSC]
,[NVarcharUTF8]
FROM [test-sc].[dbo].[UTF8Test]
SELECT TOP (1000) [Id]
,LEN([VarcharText]) VT
,LEN([VarcharTextSC]) VTSC
,LEN([VarcharUTF8]) VU
,LEN([NVarcharText]) NVT
,LEN([NVarcharTextSC]) NVTSC
,LEN([NVarcharUTF8]) NVU
FROM [test-sc].[dbo].[UTF8Test]
SELECT TOP (1000) [Id]
,DATALENGTH([VarcharText]) VT
,DATALENGTH([VarcharTextSC]) VTSC
,DATALENGTH([VarcharUTF8]) VU
,DATALENGTH([NVarcharText]) NVT
,DATALENGTH([NVarcharTextSC]) NVTSC
,DATALENGTH([NVarcharUTF8]) NVU
FROM [test-sc].[dbo].[UTF8Test]
我惊讶地发现,VARCHAR
在使用 UTF8 排序规则时,需要修改“a 只存储单字节字符”这一古老的口头禅。
- 请注意,只有表列与排序规则相关联,而不是 T-SQL 变量:
SELECT @VarcharText = [VarcharText],
@NVarcharText = [NVarcharText]
FROM [test-sc].[dbo].[UTF8Test]
WHERE [Id] = 4
SELECT @VarcharText, Len(@VarcharText), DATALENGTH(@VarcharText), @NVarcharText, Len(@NVarcharText), DATALENGTH(@NVarcharText)
SELECT @VarcharText = [VarcharTextSC],
@NVarcharText = [NVarcharTextSC]
FROM [test-sc].[dbo].[UTF8Test]
WHERE [Id] = 4
SELECT @VarcharText, Len(@VarcharText), DATALENGTH(@VarcharText), @NVarcharText, Len(@NVarcharText), DATALENGTH(@NVarcharText)
SELECT @VarcharText = [VarcharUTF8],
@NVarcharText = [NVarcharUTF8]
FROM [test-sc].[dbo].[UTF8Test]
WHERE [Id] = 4
SELECT @VarcharText, Len(@VarcharText), DATALENGTH(@VarcharText), @NVarcharText, Len(@NVarcharText), DATALENGTH(@NVarcharText)
推荐阅读
- python - 如何加载 PEM 编码证书链中的所有证书?
- r - R包开发——在帮助文件中添加图片?PackageName
- c# - C# label.text 在按钮单击时不会更改
- node.js - Discord.js 音乐机器人不响应第一个音乐请求
- java - 如何在关键短语之间获取字符串的某个部分(java)
- python - Python 无法访问命令行参数
- flutter - 可滚动屏幕 - Flutter
- python - OpenCV Python-过滤矩形以找到微型汽车的道路中心线
- javascript - ajax 没有获取会话
- php - Laravel 验证 - 不同的数组字段不起作用