将VARCHAR转换为BINARY(16)

时间:2018-04-29 14:06:26

标签: c# sql-server binary

我尝试将包含二进制数据的SQL Server列解码为varchar数据类型。

我已经在其他一些主题中看到了如何将其转换为二进制文件,但不幸的是,他们的解决方案并不适合我。

我有一个名为TABLE_TEST的表名,其中有一列名为SomeData,为varchar(400)数据类型。

如果我点击编辑表格,我看到那里有一些数据,但如果我运行一个简单的查询:

SELECT SomeData 
FROM TABLE_TEST

数据不会显示为二进制数据。

所以在其他地方读书,我继续尝试:

SELECT CONVERT(BINARY(16), SomeData, 1)  
FROM TABLE_TEST

我也尝试过风格2,它显示:

  

Msg 8114,Level 16,State 5,Line 1
  将数据类型varchar转换为varbinary时出错。

我知道这个数据完全没问题,因为当我在c#应用程序中读取它时,我只是这样做:

byte[] someDataBuffer = new byte[400];
MemoryStream someDataStream = new MemoryStream(someDataBuffer);
BinaryReader binaryReader = new BinaryReader(someDataStream);
Int32 data1 = binaryReader.ReadInt32();
Int16 data2 = binaryReader.ReadInt16();
Int16 data3 = binaryReader.ReadInt16();

有没有办法在SQL端获得相同的结果或查询? 我的意思是一个查询,它将varchar列转换为二进制,然后我可以在SQL中以相​​同的方式读取该数据结构。

EDIT1:
请注意,二进制列大小是400,所以基本上varchar(400)和我读取每个的方式是for循环50次。因为每个循环我都读取Int32然后读取Int16和Int16。这意味着总共8个字节* 50次= 400(列的大小)。

我虽然跑了这样的东西:

DECLARE @i int = 0;
WHILE @i < 50
BEGIN
    -- Read Int32
    -- Read Int16
    -- Read Int16
    SET @i = @i + 1;    
END   

但是我如何解码那里的每一部分数据呢?

EDIT2:
看起来@DavidDubois的答案是正确的方向。但我仍然不确定为什么当我尝试在SQL中读取数据时它不会起作用,这可能是一些编码问题。我添加了一张图片来展示它的样子,所以它提出了这个想法:
enter image description here
当我尝试选择此数据或复制此数据时,它不会复制任何内容。 这就是为什么它让我认为编码设置为特殊的东西。我如何检查这个?
该数据库和列的排序规则设置为:SQL_Latin1_General_CP1_CI_AS

2 个答案:

答案 0 :(得分:1)

这可以帮到你:

DECLARE @TestString VARCHAR(100) = 'Test' ;

SELECT  @TestString AS [Raw],
        CONVERT(VARBINARY(100), @TestString) AS BinaryFromString,
        CONVERT(VARCHAR(100), CONVERT(VARBINARY(100), @TestString)) AS StringFromBinary ;

您可以在此处进行测试:https://www.googleapis.com/auth/userinfo.email

答案 1 :(得分:0)

-- A varchar(400) value actually contains binary data
-- That data consists of 50 triplets.
-- Each triplet consists of a 32-bit integer, and two 16-bit integers
-- How does one pull out these values from the original data?

-- Note that data is stored in little-endian format, while SQL Server uses BIG-endian, 
-- so we need to use REVERSE

-- Declare variables to hold the triplet values
-- @i32 holds a 32-bit integer (int), while @j16 and @k16 holds 16-bit integers (smallint)
declare @i32 int
declare @j16 smallint
declare @k16 smallint

-- @C will hold the varchar(400) data
-- @B will be used to hold that same data in a binary representation
declare @C varchar(400)
declare @B varbinary(400)

-- As a test, let's first build such a string

-- The binary value starts empty
set @B = 0x

-- Loop 50 times
declare @i int
set @i=1
while @i<=50 
begin
  -- I've arbitrarily chosen values to store
  set @i32 = 1000000000-7777777 * @i
  set @j16 = @i32 % 11111
  set @k16 = @i32 % 9999

  print    'I=' + cast ( @i32 as varchar(10)) 
        + ' J=' + cast ( @j16 as varchar(10))
        + ' K=' + cast ( @k16 as varchar(10))

  -- Convert each of the three values to varbinary, and append them to the complete binary value

  set @B = @B + cast ( Reverse ( cast ( @i32 as varbinary(4))) as varbinary(4))
              + cast ( Reverse ( cast ( @j16 as varbinary(2))) as varbinary(2))
              + cast ( Reverse ( cast ( @k16 as varbinary(2))) as varbinary(2))

  set @i=@i+1
end

-- This is what it looks like in binary
select @B as [In Binary]

-- Convert that binary value to characters
set @C = cast ( @B as varchar(400))

-- Let's look at those characters.  They won't make much sense
select @C as [As Characters]

-- Now let's take that example, and reverse the process

-- Convert the character value back to binary

set @B = cast ( @C as varbinary(400))

--set @B = 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080C69706EB280100000000000000000080C69706A22601000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

-- Loop 50 times

set @i=1
while @i<50 
begin
  -- Pull out the appropriate bytes for each value, and convert those values back to integers

  set @i32 = cast( cast(Reverse(substring( @B, @i*8-7, 4 ))as varbinary(4)) as int      )

  set @j16 = cast( cast(Reverse(substring( @B, @i*8-3, 2 ))as varbinary(2)) as smallint )

  set @k16 = cast( cast(Reverse(substring( @B, @i*8-1, 2 ))as varbinary(2)) as smallint )

  -- Let's take a look
  select @i as [Idx], @i32 as [I], @j16 as [J], @k16 as [K]

  set @i=@i+1
end