web-dev-qa-db-ja.com

16進数をvarcharに変換する

16進数として保存された値を持つ列があります。

このクエリを実行すると:

select column from  table
where column like '%22639935-KCN%';

これは私が得る出力です:

0x24000000008B010000000089FF32323633393933352D4B434E000000

出力をvarcharに変換したいと思います。これにより、likeステートメントの内容に似た値が得られます。

これまでの私の試みは:

SELECT CONVERT(VARCHAR(MAX), 
       0x24000000008B010000000089FF32323633393933352D4B434E000000)


SELECT CONVERT(VARCHAR(MAX), CONVERT(VARBINARY(MAX), 
       '0x24000000008B010000000089FF32323633393933352D4B434E000000', 2))

しかし、私はこの結果を得ます:

$

この16進値をvarcharに変換するにはどうすればよいですか?

4
Blue Moon

Varbinary文字列になんらかのナンセンスが注入されているようです。 2つの_00_値のシーケンスはすべてnull文字であるため、変換時に文字列が終了します。最初の文字は_0x24_(ドル記号)です。そのため、出力は単なるドル記号です。

_SELECT CONVERT(varchar(60), 0x2400....anything....);
-- is equivalent to:
SELECT CONVERT(varchar(60), 0x24);
_

さて、あなたの文字列を取り、_00_シーケンスをすべて取り除いた場合:

_SELECT CONVERT(VARCHAR(60), 0x248B0189FF32323633393933352D4B434E);
_

私は何かに近づきます。繰り返しますが、そこには大量のゴミがありますが、あなたが求めている文字列isがあります:

_$‹‰ÿ22639935-KCN
_

元のガベージを無視して元の値を取得し、それに対してRIGHT()を実行することで無視できますが、これは文字列の重要な部分が常に同じ長さであることを前提としています(それが真であるかどうかはわかりません)。 。

_SELECT CONVERT(VARCHAR(60),     
       RIGHT(0x24000000008B010000000089FF32323633393933352D4B434E000000, 15));
_

またはSUBSTRINGを使用しますが、これは文字列の先頭のガベージが常に同じ長さであることを前提としています:

_SELECT CONVERT(VARCHAR(60), 
       SUBSTRING(0x24000000008B010000000089FF32323633393933352D4B434E000000, 14, 46));
_

whyごみがそこにあることと、それが何か追加の意味があるかどうかを伝えることもできません。最初に、値がこのようにエンコードされた方法を見つける必要があります。エンコードしたい値_22639935-KCN_は、varbinaryとは少し違って見えるはずです。

_SELECT CONVERT(VARBINARY(32), '22639935-KCN');

--------------------------
0x32323633393933352D4B434E
_

したがって、ここでも、この値がこのようにエンコードされなかった理由を見つけるために、いくつかの調査を行う必要があります。私たちはあなたのシステムを設計したりそれらの値を保存したりしていないので、これらすべてに答えることはできません。

8
Aaron Bertrand

これにより、探しているvalueが返されます。このプロセスを制御している場合は、この形式でのデータの保存を停止することを強くお勧めします。

DECLARE @hexstr nvarchar(40) = '0x' + SUBSTRING(CONVERT(NVARCHAR(100), 0x008B010000000089FF32323633393933352D4B434E000000, 1),21, 24);
declare @ind int, @byte1 int, @byte2 int, @binvalue varbinary(20)

set @binvalue = 0x

if lower(substring(@hexstr, 1, 2)) = '0x'
    set @ind = 3
else
    set @ind = 1

while ( @ind <= len(@hexstr) )
begin            
    set @byte1 = ascii(substring(@hexstr, @ind, 1))
    set @byte2 = ascii(substring(@hexstr, @ind + 1, 1))
    set @binvalue = @binvalue + convert(binary(1), 
              case 
                    when @byte1 between 48 and 57 then @byte1 - 48  
                    when @byte1 between 65 and 70 then @byte1 - 55  
                    when @byte1 between 97 and 102 then @byte1 - 87 
                    else null end * 16 +
              case 
                    when @byte2 between 48 and 57 then @byte2 - 48  
                    when @byte2 between 65 and 70 then @byte2 - 55  
                    when @byte2 between 97 and 122 then @byte2 - 87 
                    else null end) 
    set @ind = @ind + 2 
end 

SELECT CONVERT(VARCHAR(50), @binvalue)

enter image description here

これをテーブルを返す関数(いわゆるテーブル値関数)にラップするには、次のようにします。

IF COALESCE(OBJECT_ID('dbo.GetProductCodeFromVARBINARY'), 0) <> 0
BEGIN
    DROP FUNCTION dbo.GetProductCodeFromVARBINARY;
END
GO
CREATE FUNCTION GetProductCodeFromVARBINARY
(
    @Bin VARBINARY(64)
)
RETURNS @VarResults TABLE
(
    ProductCode VARCHAR(50) NULL
)
AS
BEGIN
    DECLARE @hexstr nvarchar(40) = '0x' + SUBSTRING(CONVERT(NVARCHAR(100), @Bin, 1),21, 24);
    declare @ind int, @byte1 int, @byte2 int, @binvalue varbinary(20)

    set @binvalue = 0x

    if lower(substring(@hexstr, 1, 2)) = '0x'
        set @ind = 3
    else
        set @ind = 1

    while ( @ind <= len(@hexstr) )
    begin            
        set @byte1 = ascii(substring(@hexstr, @ind, 1))
        set @byte2 = ascii(substring(@hexstr, @ind + 1, 1))
        set @binvalue = @binvalue + convert(binary(1), 
                  case 
                        when @byte1 between 48 and 57 then @byte1 - 48  
                        when @byte1 between 65 and 70 then @byte1 - 55  
                        when @byte1 between 97 and 102 then @byte1 - 87 
                        else null end * 16 +
                  case 
                        when @byte2 between 48 and 57 then @byte2 - 48  
                        when @byte2 between 65 and 70 then @byte2 - 55  
                        when @byte2 between 97 and 122 then @byte2 - 87 
                        else null end) 
        set @ind = @ind + 2 
    end 

    INSERT INTO @VarResults (ProductCode)
    VALUES (CONVERT(VARCHAR(50), @binvalue));

    RETURN;
END

これを実行するには、次のいずれかを実行できます。

SELECT *
FROM dbo.GetProductCodeFromVARBINARY(0x008B010000000089FF32323633393933352D4B434E000000);

これはこれを返します:

enter image description here

または、これをVARBINARY値を含む別のテーブルにJOINする必要がある場合は、次のようにすることができます。

CREATE TABLE dbo.VarBinValues
(
    ProdCode VARBINARY(64) NULL
);

INSERT INTO dbo.VarBinValues (ProdCode)
VALUES (0x008B010000000089FF32323633393933352D4B434E000000);

SELECT vbv.ProdCode
    , pc.ProductCode
FROM dbo.VarBinValues vbv
CROSS APPLY dbo.GetProductCodeFromVARBINARY(vbv.ProdCode) pc

結果:

enter image description here

2
Max Vernon