没有排序规则的 Unicode (UTF-16) 数据如何存储在 varchar 列中?

Posted

技术标签:

【中文标题】没有排序规则的 Unicode (UTF-16) 数据如何存储在 varchar 列中?【英文标题】:How is Unicode (UTF-16) data that is out of collation stored in varchar column? 【发布时间】:2017-04-27 06:15:04 【问题描述】:

这纯粹是理论上的问题

假设我有 Unicode 旋风 (???? 1F300) 符号。如果我尝试将其存储在具有默认Latin1_General_CI_AS 排序规则的varchar 列中,则旋风符号不能放入varchar 中每个符号使用的一个字节...

我可以看到的方式:

    就像 javascript 对基本平面之外的符号 (BMP) 所做的那样,它将它们存储为 2 个符号(代理对),然后需要对 put them back together 进行额外处理... 只需截断符号,存储第一个字节并删除第二个字节....(数据是吐司 - 你应该阅读手册......) 数据被破坏,没有任何有用的东西被保存......(数据是吐司 - 你应该阅读手册......) 其他一些超出我心理承受能力的选择.....

我在插入几个不同的 unicode 符号后做了一些研究

 INSERT INTO [Table] (Field1)
 VALUES ('????')

 INSERT INTO [Table] (Field1)
 VALUES ('????')

然后在这两种情况下将它们读取为字节SELECT cast (field1 as varbinary(10)),我得到了0x3F3F

ascii 中的3F? (question mark) 例如两个问号 (??),我在正常运行时也会看到 select * 这是否意味着数据是吐司,甚至不是第一口正在存储吗?

不符合排序规则的 Unicode 数据如何存储在 varchar 列中?

【问题讨论】:

【参考方案1】:

是的,数据已经消失了。

与NVarchar 相比,Varchar 需要的空间更少。但这种减少是有代价的。 Varchar 没有空间来存储 Unicode 字符(每个字符 1 个字节,内部查找还不够大)。

来自Microsoft's Developer Network:

...考虑使用 Unicode nchar 或 nvarchar 数据类型以尽量减少字符转换问题。

如您所见,不支持的字符用问号替换。

【讨论】:

问题不在于尺寸;它是类型的定义和行为,尤其是隐式转换。 nchar 是一种 UTF-16 编码单元;一些 Unicode 代码点需要一个,一些两个。一些数据库系统可以将 Unicode 存储为 UTF-8,其中一个代码点需要一个、两个、三个或四个 8 位代码单元。【参考方案2】:

数据是 toast 并且正是您所看到的,2 x 0x3F 字节。这发生在插入之前的类型转换期间,实际上与 cast('?' as varbinary(2)) 相同,后者也是 0xF3F3(而不是强制转换 N'?')。

当必须将 Unicode 数据插入非 Unicode 列时,这些列会在内部使用 WideCharToMultiByte API 和与排序规则关联的代码页从 Unicode 转换。如果某个字符无法在给定的代码页上表示,则该字符将替换为问号 (?) Ref。

【讨论】:

嗨,亚历克斯,感谢您的回答。我想知道为什么两个 ?? 而不是 1 个 ?,感觉像是对伤害的侮辱,哈哈...

以上是关于没有排序规则的 Unicode (UTF-16) 数据如何存储在 varchar 列中?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以让 SQL Server 将排序规则转换为 UTF-8 / UTF-16

转: utf16编码格式(unicode与utf16联系)

有没有“Unicode 排序规则”之类的东西?

一句话理解字符编码(Unicode ,UTF8,UTF16)

UTF16和UTF8啥区别 谁介绍下?

unicode字符集范围