我有一个 varbinary(max) 列,其中包含已压缩的 UTF-8 编码文本。我想解压缩这些数据并在 T-SQL 中使用 SQL Server 的 UTF-8 功能将其作为 varchar(max) 处理。
我正在寻找一种在从 varbinary(max) 转换为 varchar(max) 时指定编码的方法。我设法做到这一点的唯一方法是创建一个表变量,其中包含一个带有 UTF-8 排序规则的列,并将 varbinary 数据插入其中。
DECLARE @rv TABLE(
Res varchar(max) COLLATE Latin1_General_100_CI_AS_SC_UTF8
)
INSERT INTO @rv
SELECT SUBSTRING(Decompressed, 4, DATALENGTH(Decompressed) - 3) WithoutBOM
FROM
(SELECT DECOMPRESS(RawResource) AS Decompressed FROM Resource) t
Run Code Online (Sandbox Code Playgroud)
我想知道是否有不涉及插入表变量的更优雅和有效的方法。
更新:
将其归结为一个不处理字节顺序标记或压缩的简单示例:
我有字符串“Hello”UTF-8编码,没有存储在变量中的BOM @utf8Binary
DECLARE @utf8Binary varbinary(max) = 0x48656C6C6F20F09F988A
Run Code Online (Sandbox Code Playgroud)
现在我尝试将其分配给各种基于字符的变量并打印结果:
DECLARE @brokenVarChar varchar(max) = CONVERT(varchar(max), @utf8Binary)
print '@brokenVarChar = ' + @brokenVarChar
DECLARE @brokenNVarChar nvarchar(max) = CONVERT(varchar(max), @utf8Binary)
print '@brokenNVarChar = ' + @brokenNVarChar
DECLARE @rv TABLE(
Res varchar(max) COLLATE Latin1_General_100_CI_AS_SC_UTF8
)
INSERT INTO @rv
select @utf8Binary
DECLARE @working nvarchar(max)
Select TOP 1 @working = Res from @rv
print '@working = ' + @working
Run Code Online (Sandbox Code Playgroud)
这样做的结果是:
@brokenVarChar = Hello 😊
@brokenNVarChar = Hello 😊
@working = Hello
Run Code Online (Sandbox Code Playgroud)
所以我能够使用这种间接方法正确解码二进制结果,但我想知道是否有更直接(并且可能有效)的方法。
有一个未记录的黑客攻击:
DECLARE @utf8 VARBINARY(MAX)=0x48656C6C6F20F09F988A;
SELECT CAST(CONCAT('<?xml version="1.0" encoding="UTF-8" ?><![CDATA[',@utf8,']]>') AS XML)
.value('.','nvarchar(max)');
Run Code Online (Sandbox Code Playgroud)
结果
Hello
Run Code Online (Sandbox Code Playgroud)
即使在没有新的 UTF8 排序规则的版本中,这也适用......
更新:将其作为函数调用
这可以很容易地包装在标量函数中
CREATE FUNCTION dbo.Convert_UTF8_Binary_To_NVarchar(@utfBinary VARBINARY(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
RETURN
(
SELECT CAST(CONCAT('<?xml version="1.0" encoding="UTF-8" ?><![CDATA[',@utfBinary,']]>') AS XML)
.value('.','nvarchar(max)')
);
END
GO
Run Code Online (Sandbox Code Playgroud)
或者像这样作为内联表值函数
CREATE FUNCTION dbo.Convert_UTF8_Binary_To_NVarchar(@utfBinary VARBINARY(MAX))
RETURNS TABLE
AS
RETURN
SELECT CAST(CONCAT('<?xml version="1.0" encoding="UTF-8" ?><![CDATA[',@utfBinary,']]>') AS XML)
.value('.','nvarchar(max)') AS ConvertedString
GO
Run Code Online (Sandbox Code Playgroud)
这可以在之后使用,FROM
或者 - 更合适 - 与APPLY
我不喜欢这个解决方案,但它是我必须使用的(我最初认为它不起作用,因为似乎是 ADS 中的一个错误)。一种方法是在 UTF8 排序规则中创建一个新数据库,然后将该值传递给该数据库中的函数。由于数据库采用UTF8排序规则,因此默认排序规则将与本地不同,并返回正确的结果:
CREATE DATABASE UTF8 COLLATE Latin1_General_100_CI_AS_SC_UTF8;
GO
USE UTF8;
GO
CREATE OR ALTER FUNCTION dbo.Bin2UTF8 (@utfbinary varbinary(MAX))
RETURNS varchar(MAX) AS
BEGIN
RETURN CAST(@utfbinary AS varchar(MAX));
END
GO
USE YourDatabase;
GO
SELECT UTF8.dbo.Bin2UTF8(0x48656C6C6F20F09F988A);
Run Code Online (Sandbox Code Playgroud)
然而,这并不是特别“漂亮”。
归档时间: |
|
查看次数: |
1017 次 |
最近记录: |