【问题标题】:Cannot store particular Unicode code points / characters in NVARCHAR fields无法在 NVARCHAR 字段中存储特定的 Unicode 代码点/字符
【发布时间】:2019-07-14 02:04:47
【问题描述】:

我正在使用 SQL Server 2017 进行一些测试。 我正在尝试将任意 Unicode 代码点存储在 NVARCHAR 列中。 我尝试了不同的排序规则。 我对 Unicode 的 BMP 平面中的常用字符没有问题。

对于更多奇特的符号,例如,如果我尝试存储“????”字符(U+1D33),会发生以下情况:

  • 如果我在 Management Studio 中执行此操作,我只会看到臭名昭著的方形符号。但 Management Studio 具有正确的字体,因为我可以将其粘贴到查询编辑器中。
  • 如果我从 Visual Studio 发送文本,我在 Management Studio 中看到的值是“??”,这也是我在执行查询后从 Visual Studio 检索到的值。

我的理解是,对于非补充字符排序规则,UCS-2 子集之外的字符不应被正确解释,因为NCHAR 字段被限制为 2 个字节。

但是,我在数据库级别和列级别都尝试了Latin1_General_100_CS_AS_KS_WS_SC,但它似乎也不起作用。

有什么想法吗? 谢谢

【问题讨论】:

  • SQL Server 2017 使用 UTF16,而不是 UCS2。您是如何尝试插入和检索文本的?你是如何确定有问题的?除非您更改 Console.Output.Encoding 设置,否则控制台窗口不会显示 UTF8 文本。 Visual Studio 的输出控制台也有类似的问题。您看到 two ? 表示该单个字符的事实意味着 UTF16 序列已存储但在显示期间无法转换
  • BTW SO 本身是一个 ASP.NET 应用程序,将其数据存储在 SQL Server 数据库中。可以看到????,说明角色本身没有问题
  • SSMS 的 grid 可能也无法显示所有字符,无论字体如何。这并不意味着有问题。当我在 SSMS 中尝试这个create table #tc(name nvarchar(20)); insert into #tc values (N'????'); select name,len(name),DATALENGTH(name) from #tc; 时,我得到了???? 2 4。等待!我看到了一个正方形!但是,当我在评论中复制该方块时,出现了正确的字形

标签: sql-server tsql unicode ssms collation


【解决方案1】:

我无法重现任何数据丢失或编码问题。我可以复制复制时变为? 的正方形。这可能是由用于在 SSMS 网格或 Visual Studio 调试器窗口中显示结果的字体引起的。

SQL Server 和 Windows 使用 UTF16 已经有一段时间了,而不是 UCS-2。不过,很少有字体支持完整的 UTF16 范围。

当我在 SSMS 中尝试这个时:

create table #tc(name nvarchar(20));
insert into #tc values (N'?');

select name,len(name),DATALENGTH(name) from #tc;

我在网格中看到了一个正方形,24。这意味着字符被正确存储并占用了 4 个字节。当我尝试将这些结果复制到 SO 时,虽然我看到了:

name    (No column name)    (No column name)
?      2                    4

当我使用Result to Text 时,我得到了实际字符:

name                             
-------------------- ----------- -----------
?                   2           4

存在正确的字符,但 SSMS 网格的字体无法显示它

更新

正如 Dan Guzman 所说,字体可以从工具-->选项-->环境-->字体和颜色-->显示设置:-->网格结果。默认字体为Microsoft Sans Serif,这是一种小字体 (855KB),用作 Windows 上的默认字体。它“仅”包含 3000 个字形。不包括汉字,这就是显示方块的原因。

中国电脑默认使用 SimShun,文件大小为 17.1MB。 他们显示汉字不会有任何问题。

【讨论】:

  • 再补充一点,像select name,len(name) AS [Len],DATALENGTH(name) AS [DataLength] from #tc FOR XML PATH('test');这样的声明,你会在SSMS-grid中看到square,但是当你打开它时,XML-view会显示正确的字符。只是为了证明,这不超过 SSMS 网格中的限制。
  • 可以从 SSMS 工具菜单自定义用于网格结果的字体:工具-->选项-->环境-->字体和颜色-->显示设置:-->网格结果.
  • 谢谢。我觉得我明白了。但只是为了澄清。该字符占用 4 个字节,因此它使用代理字符。这是否意味着我需要一个 _SC 排序规则来存储这些值,或者只是我希望内置函数能够在这些值上正常运行?
  • @JosephHerraez 排序规则不会影响字符的存储方式。那总是UTF16。它会影响它们的排序和匹配方式。
  • @PanagiotisKanavos 完美。我认为现在清楚了。非常感谢。
【解决方案2】:

我正在尝试将任意 unicode 点存储在 nvarchar 列中。我尝试了不同的排序规则。我对 Unicode 的 PBS 平面中的常用字符没有问题。

排序规则与您可以在 NVARCHAR / NCHAR / NTEXT(已弃用)列、变量或文字中存储的代码点无关。这些数据类型可以存储所有 1,114,112 个 Unicode 代码点(尽管大多数尚未映射到字符)。

如果我尝试在 Management Studio 中存储 ? 字符(U+1D33), ...,我只会看到臭名昭著的方形符号。但是管理工作室有正确的字体,因为我可以将它粘贴到查询编辑器中。

正如其他人已经解释的那样:这只是一个字体问题。字体最多可容纳 65k 个字符,因此您可能需要多种字体来覆盖您尝试使用的所有字符。我更喜欢 Code2003,您可以在 FontSpace.com 上找到它。

如果我从 Visual Studio 发送文本,我在管理工作室中看到的值是 '??'

这应该是由于忘记在字符串文字前加上大写的“N”;-)。

SELECT '?' AS [Oops], N'?' AS [No Oops];
-- ??   ?

我的理解是,对于非补充字符排序规则,UCS-2 子集之外的字符不应被正确解释,因为 nchar 字段被限制为 2 个字节。

Supplementary Character-Aware (SCA) 归类——以_SC 或名称中以_140_ 结尾的排序规则——确实支持补充字符。但是,“支持”仅意味着内置函数将代理对作为单个补充代码点处理,而不是一对代理代码点。但是,对补充字符的排序和比较的支持实际上是在 SQL Server 2005 中随着版本 90 排序规则的引入而开始的。

UCS-2 和 UTF-16 中的所有代码单元都是 16 位 / 2 字节。补充字符只是那些 2 字节代码单元中的两个。因此,在引入NVARCHAR 时,SQL Server 7.0 中应该可以存储补充字符。尽管直到几年后(SQL Server 2000 发布之后)才定义补充字符,NVARCHAR 类型仍然能够存储和检索它们。我没有要测试的 SQL Server 7.0,但我已经在 SQL Server 2000 上确认了这一点。

更多信息,请参见:

【讨论】:

    猜你喜欢
    • 2012-09-06
    • 1970-01-01
    • 2019-04-26
    • 2018-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多