Sql server SQL Server从nvarchar到varbinary,然后从varbinary到nvarchar的转换保真度

Sql server SQL Server从nvarchar到varbinary,然后从varbinary到nvarchar的转换保真度,sql-server,type-conversion,Sql Server,Type Conversion,我正在尝试转换回存储在CONTEXT\u INFO中的nvarchar declare @LanguageCode nvarchar(6) = 'en'; declare @binvar varbinary(128); set @binvar = cast(@LanguageCode as varbinary); set context_info @binvar; select A = len(@LanguageCode); select B = len(convert(nvarchar(6)

我正在尝试转换回存储在CONTEXT\u INFO中的nvarchar

declare @LanguageCode nvarchar(6) = 'en';
declare @binvar varbinary(128);
set @binvar = cast(@LanguageCode as varbinary);
set context_info @binvar;

select A = len(@LanguageCode);
select B = len(convert(nvarchar(6),@LanguageCode));

select C = convert(nvarchar(6),context_info());
select D = cast(CONTEXT_INFO() as nvarchar(5));
select E = len(convert(nvarchar(6),CONTEXT_INFO()));
select F =len(cast(CONTEXT_INFO() as nvarchar(6)));

select G = convert(nvarchar,context_info());
select H = cast(CONTEXT_INFO() as nvarchar);
select I = len(convert(nvarchar,CONTEXT_INFO()));
select J = len(cast(CONTEXT_INFO() as nvarchar));
从将varbinary强制转换为nvarchar获得的nvarchar长度为6,它包括\0。例如,语言“en”返回为“en\0\0\0\0”。这弄糟了上面的密钥缓存

有没有办法将存储在varbinary中的nvarchar值转换回其原始值?i、 例如,“en”可以转换回“en”

输出:

A
-----------
2

B
-----------
2

C
------
en    

D
-----
en   

E
-----------
6

F
-----------
6

G
------------------------------
en                            

H
------------------------------
en                            

I
-----------
30

J
-----------
30
dump
--------------------
0x0000000465006E00

(1 row(s) affected)

recoveredLanguage              theLength
------------------------------ -----------
en                             2

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                2

(1 row(s) affected)
dump
----------
0x65006E00

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                6

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                2

(1 row(s) affected)
选择答案基本原理

我选择了HABO的答案,因为他的解决方案可以直接嵌入消费查询:

declare @LanguageCode nvarchar(6) = 'en';
declare @binvar varbinary(128);
set @binvar = cast(datalength(@LanguageCode) as varbinary) + cast(@LanguageCode as varbinary);
set context_info @binvar;
select dump = @binvar;



-- directly embeddable
select  recoveredLanguage = convert(nvarchar, substring(context_info(), 5, convert(int, substring(context_info(), 1, 4)) )  ) 
        , theLength =  len ( convert(nvarchar, substring(context_info(), 5, convert(int, substring(context_info(), 1, 4)) )  ) )


declare @buffer varbinary(128) = context_info();
declare @RecoveredLanguageCode nvarchar(6) = cast(substring(@buffer, 5, cast(substring(@buffer, 1, 4) as int)) as nvarchar(6));
select recoveredLanguage = @RecoveredLanguageCode, theLength = len(@RecoveredLanguageCode);
输出:

A
-----------
2

B
-----------
2

C
------
en    

D
-----
en   

E
-----------
6

F
-----------
6

G
------------------------------
en                            

H
------------------------------
en                            

I
-----------
30

J
-----------
30
dump
--------------------
0x0000000465006E00

(1 row(s) affected)

recoveredLanguage              theLength
------------------------------ -----------
en                             2

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                2

(1 row(s) affected)
dump
----------
0x65006E00

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                6

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                2

(1 row(s) affected)
虽然souplex的答案是正确的,但我不确定是全局设置ANSI_PADDING_OFF效果,还是仅对一批语句设置局部效果。把所有的铸件放在一个声明中有副作用,修复不起作用,每个铸件必须在单独的声明中进行。不管怎样,我还是支持souplex的答案

DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY(128));
SET context_info @binvar;
select dump = @Binvar;




SET ANSI_PADDING OFF;
select recoveredLanguage = cast( cast( cast(context_info() as binary(128)) as varbinary(128) ) as nvarchar(6) )
        , theLength = len( cast( cast( cast(context_info() as binary(128)) as varbinary(128) ) as nvarchar(6) ) );


DECLARE @binvar1 BINARY(128) = context_info();
DECLARE @binvar2 VARBINARY(128) = CAST(@binvar1 AS VARBINARY(128));
declare @c nvarchar(6) = cast(@binvar2 as nvarchar(6))
select recoveredLanguage = @c, theLength = len(@c);
输出:

A
-----------
2

B
-----------
2

C
------
en    

D
-----
en   

E
-----------
6

F
-----------
6

G
------------------------------
en                            

H
------------------------------
en                            

I
-----------
30

J
-----------
30
dump
--------------------
0x0000000465006E00

(1 row(s) affected)

recoveredLanguage              theLength
------------------------------ -----------
en                             2

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                2

(1 row(s) affected)
dump
----------
0x65006E00

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                6

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                2

(1 row(s) affected)

感谢HABO和souplex没有提供XML路径或XML自动解决方案:-)谢谢

在将字符串保存到
CONTEXT\u INFO
之前,在字符串前面加上长度前缀:

declare @LanguageCode nvarchar(6) = 'en';
declare @binvar varbinary(128);
set @binvar = cast(datalength(@LanguageCode) as varbinary) + cast(@LanguageCode as varbinary);
set context_info @binvar;

declare @buffer varbinary(128) = context_info();
declare @RecoveredLanguageCode nvarchar(6) = cast(substring(@buffer, 5, cast(substring(@buffer, 1, 4) as int)) as nvarchar(6));
select @RecoveredLanguageCode, len(@RecoveredLanguageCode);
普通的varbinary(128)是完全可铸造的

DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY);
SELECT  CAST(@binvar AS NVARCHAR(6));
这将返回初始值“en”

现在,当您设置上下文值并将其检索回来时,它似乎变成了二进制(128)值,而不是varbinary(128)

现在有了尾随字符(0)

当您将context_info()值强制转换为varbinary并将其强制转换为nvarchar时,当您显式地将ansi padding设置为off时,问题就解决了

SET ANSI_PADDING OFF;
--
DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY(128));
SET context_info @binvar;

SET ANSI_PADDING ON;
DECLARE @binvar1 BINARY(128) = context_info();
DECLARE @binvar2 VARBINARY(128) = CAST(@binvar1 AS VARBINARY(128));
--> having trailing char(0)
SELECT  CAST(@binvar2 AS NVARCHAR(6));

GO

DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY(128));
SET context_info @binvar;

SET ANSI_PADDING OFF;
DECLARE @binvar1 BINARY(128) = context_info();
DECLARE @binvar2 VARBINARY(128) = CAST(@binvar1 AS VARBINARY(128));
--> no more trailing char(0)
SELECT  CAST(@binvar2 AS NVARCHAR(6));

为什么不“声明@binvar varbinary(4);”?刚好可以容纳字符,并且没有尾随字符\0\0\0\0@KhanhTO有些语言代码不是固定长度的。e、 例如,en-US,zh-CN,zh-TW,zh-CHS,zh-cht或只是在第一个
char(0)
@ErikE处截断-我倾向于保留我开始的信息,而不是采取
c
的态度,即
\0
必须是结尾。使用
'en'+char(0)+'x'
的初始字符串进行测试,结果正确地重新创建了该字符串。初始字符串和重新创建的字符串都显示为
en
,但是将它们转换为
varbinary(128)
表明它仅仅是由SSM在
\0
处停止引起的显示工件。