将Unicode转换为非Unicode /将NVARCHAR转换为VARCHAR时自动翻译


8

Unicode代码点9619是一个称为“深色阴影”的字符:http://unicode-table.com/en/search/?q=9619)。

使用SQL_Latin1_General_CP1_CI_AS归类和1252代码页,我希望将Unicode字符转换/转换为非Unicode数据类型将导致出现问号(?),因为代码页1252似乎不包含此字符,并且这似乎是SQL Server的无法进行转换时的行为。

所以我的问题是:为什么SQL Server将此字符转换为ASCII代码166,即“管道,竖线损坏”:¦

SELECT NCHAR(9619), CAST(NCHAR(9619) AS CHAR(1)), ASCII(CAST(NCHAR(9619) AS CHAR(1)))

3
SQL Server使用本文所说的同形转换,并经常将无法表示的字符转换为近似等价的字符。例如丢失字符的重音或将智能引号更改为纯引号。我同意那看起来并不太紧密!我不确定这些转换是否或在何处记录。
马丁·史密斯

哇,不知道... je,看起来好像不对...不是同一个人。为什么不只是一个“ ...哎呀,在此代码页中找不到此类字符...”而使转换失败?
李·亨利(Henry Lee)

1
刚刚阅读此页并记住了这一点。不确定SQL Server是否使用完全相同的“最佳匹配”算法。
马丁·史密斯

1
@MartinSmith关于不确定SQL Server的“最适合”映射,请在找到这些映射时查看下面的答案:-)。
所罗门·鲁兹基

Answers:


8

SQL为什么将Unicode 9619转换为ASCII代码166?

SQL Server在这里不使用任何特殊的自定义逻辑;它正在使用标准操作系统服务来执行转换。

具体地,SQL Server的类型和表达服务(sqlTsEs)调用到OS程序WideCharToMultiBytekernel32.dll。SQL Server将输入参数设置为WideCharToMultiByte,以便例程执行“快速转换”。这比不存在直接转换时要求使用特定默认字符的速度更快。

快速翻译依赖于目标代码页来对任何不匹配的字符执行最佳匹配映射,如马丁·史密斯在问题注释中提供的链接中所述:

最佳策略针对不同的代码页而有所不同,因此没有详细记录。

将输入参数设置为快速翻译后,WideCharToMultiByte将调用OS服务GetMBNoDefaultsource)。在执行问题中指定的转换时检查SQL Server调用堆栈可以确认这一点:

SQL Server堆栈跟踪


7

从Unicode数据到特定代码页的转换采用了所谓的“最佳匹配”策略(如@Paul 的回答以及@Martin在对问题的评论中指出的链接中所述)。根据.NET Framework中用于字符编码的 MSDN页面:

最佳匹配映射是将Unicode数据编码为代码页数据的Encoding对象的默认行为...

但是这些映射到底是什么?该MSDN页面用于声明以下内容:

最佳策略针对不同的代码页而有所不同,因此没有详细记录。

但是,这并不完全正确。可能没有准确记录确定映射的“策略”。好。但是,映射本身记录在案,只是不是在最容易找到的地方。

因此,感谢Microsoft将文档移至GitHub,该页面现在显示以下内容(因为我已对其进行了更新):

没有详细记录最佳策略。但是,在Unicode联盟的网站上记录了一些代码页。请查看该文件夹中的readme.txt文件,以获取有关如何解释映射文件的描述。

如果转到以下URL,将看到几个文件的列表,每个文件都以将Unicode字符映射到的代码页命名:

ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/

大多数文件最后一次更新(或至少放置在2006年10月4日),其中一个文件于2012-03-14更新。这些文件的第一部分将ASCII代码映射到等效的Unicode代码点。但是,每个文件的第二部分将Unicode字符映射到其ASCII“等效项”。

我编写了一个测试脚本,该脚本使用“代码页1252”映射来检查SQL Server是否确实在使用这些映射。可以通过回答以下两个问题来确定:

  1. 对于所有映射的代码点,SQL Server是否将它们转换为指定的映射?
  2. 对于所有未映射的代码点,SQL Server是否将其中的任何一个转换为非?字符?

测试脚本太长,无法在此处放置,因此我将其发布在Pastebin上的位置:

SQL Server中的Unicode到代码页的映射

运行脚本将显示,上面第一个问题的答案为“是”(意味着将遵守所有提供的映射)。它还将显示第二个问题的答案为“否”(意味着,未映射的代码点除“ unknown”字符外均不会转换为其他任何字符)。因此,该映射文件非常准确:-)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.