Search code examples
sqlsql-serversql-server-2008t-sqlcdc

Sql server conversion issues from Binary Data type to Numeric data


I am trying to persist values from one of the Sql server CDC table, which has column data type as "Binary(10)". I want to convert it into "Numeric" format and then convert it back to "Binary(10)".

For e.g.

declare @binary_data binary(10),@binary2 as binary(10)

select  @binary_data = 0x000000180003727C0006

Select Convert(int,0x00000018) as [PrecesionValue]
Select Convert(int,0x000) as [ScaleValue]

declare @Numeric as numeric(24,0) --Setting Numeric(PrecesionValue, ScaleValue)

Select @Numeric =Convert(numeric(24,0),@binary_data) 

Select @binary2 = Convert(binary(10),@Numeric) 

print @binary_data
print @Numeric
print @binary2

Output:

0x000000180003727C0006  //Initial binary data

393340                  //Converted Numeric value

0x0000180000017C000600  //Re-converted back to Binary value

If you see, the Re-convetred Binary value doesnt match the original value. Can you please check where I am going wrong?


Solution

  • To "translate" a 10-byte binary to something non-binary you'd need a data type, which has at least 10 bytes storage space. But you should not rely on the bit pattern used by SQL Server to store a complex data type.

    I want to suggest two approaches:

    --this is your binary
    declare @binary1 binary(10) 
    set @binary1 = 0x000000180003727C0006;
    select  @binary1; 
    
    --XML will translate binaries to base64 implicitly
    declare @string varchar(100);
    set @string = (SELECT @binary1 AS [*] FOR XML PATH(''),TYPE).value('.','varchar(100)');
    select @string,LEN(@string);
    
    --this is the approach to translate the base64 back to a binary
    declare @binary2 binary(10);
    set @binary2=CAST('<x>' + @string + '</x>' AS XML).value('.','varbinary(10)');
    select @binary2; 
    
    --the second approach is a GUID (16 byte)
    declare @guid uniqueidentifier;
    set @guid=@binary1
    select @guid;
    
    --a GUID is a simple chain of bytes, easy to cast
    set @binary2=CAST(@guid AS VARBINARY(10));
    select @binary2; 
    

    UPDATE: one more idea came to my mind

    There's a reason, why binary and string types are disussed in one topic. You can split your 10 byte binary in chunks and take them as separated numbers:

    declare @binary1 binary(10) 
    set @binary1 = 0x00000180003727C0006;
    select  @binary1,SUBSTRING(@binary1,1,4) AS Byte0to3 
                    ,SUBSTRING(@binary1,5,4) AS Byte4to8
                    ,SUBSTRING(@binary1,10,2) AS Byte9to10;
    
    declare @int1 INT, @int2 INT, @smallint smallint;
    select  @int1 =     SUBSTRING(@binary1,1,4)  
           ,@int2 =     SUBSTRING(@binary1,5,4) 
           ,@smallint = SUBSTRING(@binary1,10,2);
    select @int1,@int2,@smallint;
    
    declare @binary2 binary(10);
    set @binary2 = CAST(@int1 AS binary(4)) + CAST(@int2 AS binary(4)) + CAST(@smallint AS binary(2));
    select @binary2;