如何将 SQL Server Unicode / NVARCHAR 字符串设置为表情符号或补充字符?

Ril*_*jor 32 sql-server collation t-sql encoding unicode

我想根据其 Unicode 代码点将 Unicode 字符串变量设置为特定字符。

我想使用 65535 以外的代码点,但 SQL Server 2008 R2 数据库的排序规则为SQL_Latin1_General_CP1_CI_AS.

根据Microsoft 的 NCHAR 文档,该NCHAR函数采用如下整数:

整数表达式

当数据库的排序规则不包含补充字符 (SC) 标志时,这是一个从 0 到 65535(0 到 0xFFFF)的正整数。如果指定了超出此范围的值,则返回 NULL。有关补充字符的更多信息,请参阅排序规则和 Unicode 支持。

当数据库的排序规则支持补充字符 (SC) 标志时,这是一个从 0 到 1114111(0 到 0x10FFFF)的正整数。如果指定了超出此范围的值,则返回 NULL。

所以这段代码:

SELECT NCHAR(128512);
Run Code Online (Sandbox Code Playgroud)

NULL在此数据库中返回。

我希望它返回与此相同的:

SELECT N'';
Run Code Online (Sandbox Code Playgroud)

如何在排序规则“不包含补充字符 (SC) 标志”的数据库中使用代码(不使用实际表情符号字符)将 Unicode 字符串变量(例如 nvarchar)设置为表情符号?

表情符号 Unicode 代码点的完整列表

(最终我希望任何角色都能工作。我只是为了便于参考而选择了表情符号。)

(虽然服务器是SQL Server 2008 R2,但我也很好奇以后版本有什么解决方案。)

假设没有办法,我可以在另一个具有适当排序规则的数据库中引用内联用户定义函数吗?

如何找到具有“补充字符”标志的归类?

这在我们的服务器上不返回任何记录:

SELECT * FROM sys.fn_helpcollations() 
WHERE name LIKE 'SQL%[_]SC';
Run Code Online (Sandbox Code Playgroud)

似乎引入了 SQL Server 2012Latin1_General_100_CI_AS_SC可以工作。您可以在旧实例上安装排序规则吗?

整理参考:

有没有解释为什么除了从NCHAR.

Sol*_*zky 48

UCS-2 编码始终为每个字符 2 个字节,范围为 0 - 65535 (0x0000 - 0xFFFF)。UTF-16(无论是大端还是小端)的范围是 0 - 1114111 (0x0000 - 0x10FFFF)。UTF-16 的 0 - 65535 / 0x0000 - 0xFFFF 范围是每个字符 2 个字节,而 65536 / 0xFFFF 以上的范围是每个字符 4 个字节。

Windows 和 SQL Server 开始使用 UCS-2 编码,因为它可用并且 UTF-16 尚未最终确定。幸运的是,UCS-2 和 UTF-16 的设计有足够的先见之明,UCS-2 映射是 UTF-16 映射的完整子集(意思是:0 - 65535 / 0x0000 - 0xFFFF 范围UTF-16UCS-2)。并且,UTF-16 的 65536 - 1114111 (0x10000 - 0x10FFFF) 范围是由 UCS-2 范围内的两个代码点(特别是范围 0xD800 - 0xDBFF 和 0xDC00 - 0xDFFF)构成的,这些代码点没有为此目的而保留,否则意义。两个代码点的这种组合称为代理对,代理对代表超出 UCS-2 范围的字符,称为补充字符。

所有这些信息都解释NVARCHAR了 SQL Server中/ Unicode 数据的两个方面:

  1. 几个内置函数(不仅仅是NCHAR())在不使用补充字符识别排序规则(SCA;即一个带有_SC _140_但不在_BIN*名称中)时不处理代理对/补充字符,因为非 SCA 排序规则(尤其是SQL_排序规则)最初是在 UTF-16 完成之前实现的(我相信是在 2000 年的某个时候)。在名称SQL_中具有_90_或的非排序规则_100__SC在比较和排序方面对补充字符的支持最少。
  2. 完整的Unicode / UTF-16字符集可以被存储,而没有任何数据丢失,在NVARCHAR/ NCHAR/ XML/NTEXT数据类型,因为UCS-2和UTF-16是完全相同的字节序列。唯一的区别是 UTF-16 使用代理代码点来构造代理对,而 UCS-2 根本无法将它们映射到任何字符,因此它们在内置函数中表现为两个未知字符。

考虑到这些背景信息,我们现在可以解决具体问题:

我想SELECT NCHAR(128512);返回与此相同的:SELECT N'';

仅当当前数据库(执行查询的位置)具有补充字符识别的默认排序规则时才会发生这种情况,并且 SQL Server 2012 中引入了这些排序规则。具有字符串输入参数的内置函数可以提供提供的排序规则通过内嵌的COLLATE条款(即LEN(N'string' COLLATE Some_Collation_SC)),并不需要将一个具有SCA缺省归类的数据库中执行。但是,诸如NCHAR()接受INT输入参数之类的内置函数COLLATE在该上下文中无效(这就是为什么NCHAR()仅当当前数据库具有补充字符感知的默认排序规则时才支持补充字符的原因;但这是不必要的)可以更改的不便,所以请投票支持我的建议:NCHAR() 函数应始终为值 0x10000 - 0x10FFFF 返回补充字符,而不管活动数据库的默认排序规则) 。

有没有解释为什么除了从NCHAR.

此答案的顶部部分解释了 SQL Server 如何在不丢失数据的情况下存储和检索补充字符。但是,这不是NCHAR唯一存在补充字符问题的内置函数(当不使用 SCA 排序规则时)。例如,LEN(N'' COLLATE SQL_Latin1_General_CP1_CI_AS)返回值 2 而LEN(N'' COLLATE Latin1_General_100_CI_AS_SC)返回值 1。

如果您转到问题中发布的第二个链接(即“Microsoft 的补充字符整理信息”)并向下滚动一点,您将看到内置函数的图表以及它们根据有效整理的行为方式。

如何找到具有“补充字符”标志的归类?

在 2012 年之前的 SQL Server 版本中,您不能。但是,从 SQL Server 2012 开始,您可以使用以下查询:

SELECT col.*
FROM   sys.fn_helpcollations() col
WHERE  col.[name] LIKE N'%[_]SC'
OR     col.[name] LIKE N'%[_]SC[_]%'
OR     (COLLATIONPROPERTY(col.[name], 'Version') = 3
      AND col.[name] NOT LIKE N'%[_]BIN%');
Run Code Online (Sandbox Code Playgroud)

您的查询很接近,但模式以 开头,SQL并且 SQL Server 排序规则(即以 开头的那些SQL_)已经被弃用了一段时间,以支持 Windows 排序规则(那些不以 开头的SQL_)。因此,SQL_排序规则没有更新,因此没有包含该_SC选项的更新版本(从 SQL Server 2017 开始,所有新排序规则都自动支持补充字符,不需要或没有_SC标志;是的,查询紧接上面显示的帐户以及获取_UTF8SQL Server 2019 中添加的排序规则)。

您可以在旧实例上安装排序规则吗?

不可以,您不能将排序规则安装到 SQL Server 的早期版本中。

如何在排序规则“不包含增补字符 (SC) 标志”的数据库中使用代码(不使用实际增补字符)将 Unicode 字符串变量(例如 nvarchar)设置为增补字符?
...
虽然服务器是SQL Server 2008 R2,但我也很好奇以后版本有什么解决方案。

不使用 SCA 排序规则时,您可以通过两种方式注入 65535 / U+FFFF 以上的代码点:

  1. 根据对NCHAR()函数的两次调用来指定代理对,每个调用都包含该对的一部分
  2. 根据转换VARBINARYLittle Endian(即反向)字节序列的形式指定代理对。

即使有效的排序规则是可识别补充字符的,这两种插入补充字符/代理对的方法也可以工作,并且应该在所有版本的 SQL Server 中都一样工作,至少可以追溯到 2005 年(尽管可能也适用于SQL Server 2000 也是如此)。

例子:

  • 特点:

                       

  • 名称:                一堆便便
  • 十进制:            128169
  • 代码点:       U+1F4A9
  • 代理对: U+D83D & U+DF21
SELECT N'', -- 
       UNICODE(N'' COLLATE Latin1_General_100_CI_AS), -- 55357
       UNICODE(N'' COLLATE Latin1_General_100_CI_AS_SC), -- 128169
       NCHAR(128169), --  in DB with _SC Collation, else NULL
       NCHAR(0x1F4A9), --  in DB with _SC Collation, else NULL
       CONVERT(VARBINARY(4), 128169), -- 0x0001F4A9
       CONVERT(VARBINARY(4), N''), -- 0x3DD8A9DC
       CONVERT(NVARCHAR(10), 0x3DD8A9DC), --  (regardless of DB Collation)
       NCHAR(0xD83D) + NCHAR(0xDCA9) --  (regardless of DB Collation)
Run Code Online (Sandbox Code Playgroud)

更新

您可以使用以下 iTVF从 65536 - 1114111 (0x010000 - 0x10FFFF) 之间的任何代码点获取代理对值(以两种形式INTBINARY形式)。而且,虽然输入参数的类型是INT,但您可以传入代码点的二进制/十六进制形式,它将隐式转换为正确的整数值。

CREATE FUNCTION dbo.GetSupplementaryCharacterInfo(@CodePoint INT)
RETURNS TABLE
WITH SCHEMABINDING
AS RETURN

WITH calc AS
(
  SELECT 55232 + (@CodePoint / 1024) AS [HighSurrogateINT],
         56320 + (@CodePoint % 1024) AS [LowSurrogateINT]
  WHERE  @CodePoint BETWEEN  65536 AND 1114111
)
SELECT @CodePoint AS [CodePointINT],
       HighSurrogateINT,
       LowSurrogateINT,
       CONVERT(VARBINARY(3), @CodePoint) AS [CodePointBIN],
       CONVERT(BINARY(2), HighSurrogateINT) AS [HighSurrogateBIN],
       CONVERT(BINARY(2), LowSurrogateINT) AS [LowSurrogateBIN],
       CONVERT(binary(4), NCHAR(HighSurrogateINT) + NCHAR(LowSurrogateINT)) AS [UTF-16LE],
       NCHAR(HighSurrogateINT) + NCHAR(LowSurrogateINT) AS [Character]
FROM   calc;
GO
Run Code Online (Sandbox Code Playgroud)

使用上面的函数,进行以下两个查询:

SELECT * FROM dbo.GetSupplementaryCharacterInfo(128169);

SELECT * FROM dbo.GetSupplementaryCharacterInfo(0x01F4A9);
Run Code Online (Sandbox Code Playgroud)

两者都返回以下内容:

CodePoint  HighSurrogate  LowSurrgate  CodePoint  HighSurrgate  LowSurrgate  UTF-16LE   Char
INT        INT            INT          BIN        BIN           BIN                     actr
128169     55357          56489        0x01F4A9   0xD83D        0xDCA9       0x3DD8A9DC   
Run Code Online (Sandbox Code Playgroud)

更新 2:更好的更新!

我已经修改了上面显示的 iTVF,现在返回 188,657 个代码点,因此您不需要为它设置任何特定值。当然,作为一个 TVF,您可以添加一个WHERE子句来过滤特定的代码点、代码点范围或“相似字符”等。并且,它包括带有预格式化转义序列的附加列来构建每个代码点(BMP 和补充字符)在 T-SQL(不需要“ _SC”或“ _140_”排序规则)、HTML(和 XML),许多应用程序语言的通用样式(“\uHHHH”;用于 C++/C#/F# / Java / JavaScript / Julia / 等),最后是处理所有代码点的稍新的其他常见样式,而不仅仅是 BMP(“\UHHHHHHHH”;用于 C / C++ / C# / F# / Julia / 等)。

在这里阅读所有相关信息:

SSMS 提示 #3:轻松访问/研究所有 Unicode 字符(是的,包括表情符号 ?)

  • 伟大的工作所罗门!很棒的解释 (4认同)