如何在 SQL Server 数据库中使用 UTF-8 排序规则?

Posted

技术标签:

【中文标题】如何在 SQL Server 数据库中使用 UTF-8 排序规则?【英文标题】:How to Use UTF-8 Collation in SQL Server database? 【发布时间】:2012-09-12 19:45:12 【问题描述】:

我已将数据库从 mysql 迁移到 SQL Server(政治),使用 UTF8 的原始 mysql 数据库。

现在我读到https://dba.stackexchange.com/questions/7346/sql-server-2005-2008-utf-8-collation-charset,SQL Server 2008 不支持 utf8,这是在开玩笑吗?

SQL Server 托管多个数据库,大部分是拉丁编码的。由于迁移的数据库是用于网络发布的,所以我想保留 utf8 编码。我是否遗漏了什么,或者我需要在应用程序级别进行编码/解码?

【问题讨论】:

其实使用UTF8是没有问题的,通过创建SQLCLR UDF,你可以从微软下载代码。检查此链接:technet.microsoft.com/en-us/library/ms160893(v=sql.90).aspx 值得注意的是,Java、javascript、DotNet 和 Windows 都在内部使用 UTF-16,因此如果您的网站要使用其中任何一种编码,那么您将保存转换为 UTF16。 如果有帮助,您可以假设 SQL Server 在内部将文本存储为 UTF-8;当您检索它时,驱动程序会将其转换回 UTF-16。您还可以假设 SQL Server 将文本存储为 UCS-32。内部存储格式是一个不相关的实现细节。重要的是数据库将 unicode 字符数据作为 UTF-16(匹配您的编程环境)返回。 【参考方案1】:

看起来这将在 SQL Server 2019 中最终得到支持! SQL Server 2019 - whats new?

来自 BOL:

UTF-8 支持

完全支持广泛使用的 UTF-8 字符编码作为导入 或导出编码,或作为数据库级或列级排序规则 文本数据。 CHARVARCHAR 数据类型中允许使用 UTF-8,并且是 在创建或将对象的排序规则更改为排序规则时启用 带有UTF8 后缀。

例如,LATIN1_GENERAL_100_CI_AS_SCLATIN1_GENERAL_100_CI_AS_SC_UTF8。 UTF-8 仅适用于 Windows 支持补充字符的排序规则,如 SQL 中所介绍的 服务器 2012。NCHARNVARCHAR 仅允许 UTF-16 编码,并保持 不变。

此功能可能会显着节省存储空间,具体取决于 正在使用的字符集。例如,更改现有列数据 使用 UTF-8 输入从 NCHAR(10)CHAR(10) 的 ASCII 字符串 启用排序规则,将存储空间减少近 50% 要求。这种减少是因为NCHAR(10) 需要 22 个字节 用于存储,而CHAR(10) 需要 12 个字节用于相同的 Unicode 字符串。

2019-05-14 更新:

文档现在似乎已更新,并在“Collation and Unicode Support”部分解释了我们在 MSSQL 2019 中的选项。

2019-07-24 更新:

Article by Pedro Lopes - 高级项目经理@Microsoft 关于为 Azure SQL 数据库引入 UTF-8 支持

【讨论】:

告售者:sqlquantumleap.com/2018/09/28/…【参考方案2】:

在T-SQL中处理UTF-8的两个UDF:

CREATE Function UcsToUtf8(@src nvarchar(MAX)) returns varchar(MAX) as
begin
    declare @res varchar(MAX)='', @pi char(8)='%[^'+char(0)+'-'+char(127)+']%', @i int, @j int
    select @i=patindex(@pi,@src collate Latin1_General_BIN)
    while @i>0
    begin
        select @j=unicode(substring(@src,@i,1))
        if @j<0x800     select @res=@res+left(@src,@i-1)+char((@j&1984)/64+192)+char((@j&63)+128)
        else            select @res=@res+left(@src,@i-1)+char((@j&61440)/4096+224)+char((@j&4032)/64+128)+char((@j&63)+128)
        select @src=substring(@src,@i+1,datalength(@src)-1), @i=patindex(@pi,@src collate Latin1_General_BIN)
    end
    select @res=@res+@src
    return @res
end

CREATE Function Utf8ToUcs(@src varchar(MAX)) returns nvarchar(MAX) as
begin
    declare @i int, @res nvarchar(MAX)=@src, @pi varchar(18)
    select @pi='%[à-ï][€-¿][€-¿]%',@i=patindex(@pi,@src collate Latin1_General_BIN)
    while @i>0 select @res=stuff(@res,@i,3,nchar(((ascii(substring(@src,@i,1))&31)*4096)+((ascii(substring(@src,@i+1,1))&63)*64)+(ascii(substring(@src,@i+2,1))&63))), @src=stuff(@src,@i,3,'.'), @i=patindex(@pi,@src collate Latin1_General_BIN)
    select @pi='%[Â-ß][€-¿]%',@i=patindex(@pi,@src collate Latin1_General_BIN)
    while @i>0 select @res=stuff(@res,@i,2,nchar(((ascii(substring(@src,@i,1))&31)*64)+(ascii(substring(@src,@i+1,1))&63))), @src=stuff(@src,@i,2,'.'),@i=patindex(@pi,@src collate Latin1_General_BIN)
    return @res
end

【讨论】:

【参考方案3】:

请注意,自 Microsoft SQL Server 2016 起,bcpBULK_INSERTOPENROWSET 支持 UTF-8。

附录 2016-12-21:SQL Server 2016 SP1 现在为所有版本的 MS SQL(包括 Standard 和 Express)启用 Unicode 压缩(以及大多数其他以前仅限企业使用的功能)。这与 UTF-8 支持不同,但如果目标是减少西方字母的磁盘空间,它会产生类似的好处。

【讨论】:

但不是 OPENQUERY?我想知道这是否是我在使用 OPENQUERY 从 Oracle 迁移 CLOB 数据时遇到问题的原因。【参考方案4】:

不!这不是开玩笑。

看这里:http://msdn.microsoft.com/en-us/library/ms186939.aspx

固定长度、nchar 或 可变长度、nvarchar、Unicode 数据并使用 UNICODE UCS-2 字符集。

还有这里:http://en.wikipedia.org/wiki/UTF-16

较旧的 UCS-2(2 字节通用字符集)是一个类似的 在 2.0 版本中被 UTF-16 取代的字符编码 1996 年 7 月的 Unicode 标准。

【讨论】:

好的。 mssql-client 可以翻译到外部的 UTF8 世界吗? mssql-client 可以是一切。 Java、.NET、C、php 等...客户端是什么意思? 客户端:php下的sqlsrv扩展。罗伯特在这里写明文:social.msdn.microsoft.com/Forums/en/sqldriverforphp/thread/…,将评估并发布结果。 您好,抱歉耽搁了,但感谢代表,在连接字符串中使用 sqlsrv_connect(,array("CharacterSet" => "UTF-8").. 工作正常。PDO 出来了,对吗?【参考方案5】:

UTF-8 不是字符集,它是一种编码。 UTF-8 的字符集是 Unicode。如果要存储 Unicode 文本,请使用 nvarchar 数据类型。

如果数据库使用 UTF-8 存储文本,您仍然无法将文本作为编码的 UTF-8 数据导出,而是将其作为解码文本导出。

您可以轻松地将 UTF-8 编码的文本存储在数据库中,但是您不会将其存储为文本,而是将其存储为二进制数据 (varbinary)。

【讨论】:

感谢您的意见。还有更多要了解的内容,例如 ***.com/questions/3951722/… 我无法理解这一点。 “UTF8 的字符集是 Unicode”?? utf8 不是比 unicode 更广泛。将 Dauðalogn 保存为 unicode vs utf8 会给出不同的结果: (EF BB BF) 44 61 75 C3 B0 61 6C 6F 67 6E vs \u0044\u0061\u0075\u00f0\u0061\u006c\u006f\u0067\u006e @user247245:UTF-8 是编码,Unicode 是字符集。 UTF-8 是保存 Unicode 的一种方式。您用来表示 Unicode 的是字符串文字中使用的转义码,这通常不是您将 Unicode 表示为文件的方式。 UTF-32 是直接从 Uncode 到文件格式的最接近的翻译,其中每个字符代码都保存为 32 位数字。 您能否解释一下为什么上面示例中的第三个字母在 UTF8 中表示为 C3 B0 而在 unicode 中表示为 F0 。感谢您的帮助。 @user247245:8到11位之间的字符代码在UTF-8中编码为110xxxxx 10xxxxxx(其中x代表数据位),所以字符代码F000011110000为11 位)被编码为11000011 10110000(将00011 放在第一个字节的字符代码中,将110000 放在第二个字节中)即C3 B0

以上是关于如何在 SQL Server 数据库中使用 UTF-8 排序规则?的主要内容,如果未能解决你的问题,请参考以下文章

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

SQL SERVER 2008 如何将字符集更改为UTF-8

UCS-2 和 SQL Server

python中pymssql如何向sql server插入数据 插入的值可以用变量替换

如何使用sql server数据库中的标量值函数

sql server中如何实现在异地访问数据库