没有排序规则的 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