问题
Scenario:
I am inserting a string into a binary field (CONTEXT_INFO) and then later attempting to pull it out and convert it back to a string. When I do, the resulting string has a length of 128 because it has trailing null characters.
Example:
DECLARE @string VARCHAR(128)
DECLARE @binary VARBINARY(128)
SET @string = 'abcdefg'
SET @binary = CONVERT(VARBINARY(128), @string) --0x61626364656667000000...
SET CONTEXT_INFO @binary
SET @binary = CONTEXT_INFO()
-- I would like to change the following line so it trims trailing null chars
SET @string = CONVERT(VARCHAR(128), @binary)
SELECT
@binary AS [binary],
DATALENGTH(@binary) AS [binary.Length], --128 as expected
@string AS [string],
DATALENGTH(@string) AS [string.Length] --This is 128, but I need it to be 7
Question:
How can I trim the trailing null characters when I convert the binary field to a string?
回答1:
Try this, works on Sql-Server 2008.
Here is Sql Fiddle.
Please note that I am assuming that the original string has NOT got Char(0) in it as this could simply replace it even from the original string.
-- I would like to change the following line so it trims trailing null chars
SET @string = CONVERT(VARCHAR(128), @binary)
SET @string = REPLACE(@string, Char(0),'')
回答2:
Here was my solution. I went this way because of what CONTEXT_INFO makes the value look like (pads to the right).
DECLARE @string VARCHAR(128)
DECLARE @binary VARBINARY(128)
SET @string = 'abcdefg'
SET @string = REPLICATE(CHAR(0),128-LEN(@string))+@string
SET @binary = CONVERT(VARBINARY(128), @string)
SET CONTEXT_INFO @binary
SET @binary = CONTEXT_INFO()
SET @string = CONVERT(VARCHAR(128), REPLACE(@binary,CHAR(0),''))
SELECT
@binary AS [binary],
DATALENGTH(@binary) AS [binary.Length],
@string AS [string],
DATALENGTH(@string) AS [string.Length]
回答3:
For the record, this will trim the trailing 0x00 and leave the 0x00 in place if they happen in the middle of the data:
cast(substring(CONTEXT_INFO(), 1, len(REPLACE(REPLACE(CONTEXT_INFO(), 0x20, 0x21), 0x00, 0x20))) as varbinary(128))
This gives a result as a varbinary, if you want a string, remove the outer cast
Most of the other solutions either end up removing the 0x00 in the middle, or changing it to a 0x20.
回答4:
Converting from nvarchar(x)
to varbinary(x)
back to nvarchar(x)
will always round-trip correctly. The core issue described here occurs because SELECT CONTEXT_INFO()
always returns 128 bytes, regardless of the length of the varbinary source used to set CONTEXT_INFO
.
There are two workarounds.
First workaround: starting in SQL Server 2016, sp_set_session_context may be used to set the vastly superior session_context.
Second workaround: context_info
can be retrieved from sys.dm_exec_sessions in the way CONTEXT_INFO()
should work. This query will return the context_info
associated with the current connection:
SELECT context_info FROM sys.dm_exec_sessions WHERE session_id = @@SPID
Here's a comparison of the two retrieval methods in SSMS:
SET CONTEXT_INFO 0x010200340056;
GO
SELECT CONTEXT_INFO(); -- 0x0012003400560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
SELECT context_info FROM sys.dm_exec_sessions WHERE session_id = @@SPID; -- 0x001200340056
SET CONTEXT_INFO 0x;
GO
SELECT CONTEXT_INFO(); -- NULL
SELECT context_info FROM sys.dm_exec_sessions WHERE session_id = @@SPID; -- 0x
Caveat: Setting CONTEXT_INFO
should be executed in a batch separate from retrieving context_info
via sys.dm_exec_sessions
(as seen above via the SSMS batch-separator GO
).
来源:https://stackoverflow.com/questions/14162672/right-trimming-binary-data-in-sql-server