如何将十六进制数据字符串转换为字符串db2 sql

时间:2019-03-15 08:08:20

标签: sql db2 db2-400 rpgle

如何使用选择语句解码十六进制字符串以获取文本格式的值?

例如,我的十六进制数据是:

4f004e004c005900200046004f00520020004200410043004b002d005500500020004f004e0020004c004500560045004c0020004f004e004500200046004f00520020004300520041004e004500530020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020000000

我想使用select语句对其进行解码以获取字符串值。 上面的值是“仅用于第一个级别的备份”

我尝试过的是:

    SELECT CAST('4f004e004c005900200046004f00520020004200410043004b002d005500500020004f004e0020004c004500560045004c0020004f004e004500200046004f00520020004300520041004e004500530020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020000000' 
    AS VARCHAR(30000) CCSID 37) from myschema.atable

上面的sql返回我期望的完全相同的十六进制字符串,而不是“仅用于一级备份的”解码文本字符串。

是否可以使用演员表来做到这一点?如果是这样,语法是什么?

我的问题是系统将文本数据存储在blob字段中,我想使用select语句查看blob字段中的文本数据。

Db:Ibm上的Db2

编辑:

我设法通过使用:将字符串隐蔽为十六进制值:

    select hex(cast('ONLY FOR BACK-UP ON LEVEL ONE FOR CRANES' as varchar(100) ccsid 1208))
FROM myschema.atable

这给了我十六进制的字符串:

4F4E4C5920464F52204241434B2D5550204F4E204C4556454C204F4E4520464F52204352414E4553

现在我需要以某种方式进行逆运算并获取值。

谢谢。

修改

使用Daniel Lema的答案,我尝试使用unhex函数,但得到的结果是:

|+<ßã|êâ ä.í&|+<áîá<|+áã|êäê +áë

这与CSSID有关吗?还是应该让上面的内容成为可读的字符串?

这是表字段定义,如果它将有助于将我的数据放入GDTXFT BLOB中的字段:

enter image description here

5 个答案:

答案 0 :(得分:1)

我能够将您缩短的十六进制字符串转换为有效的EBCDIC字符串。 我遇到的问题是,您收到的原始十六进制代码来自UTF-16LE(感谢Tom Blodget)。 IBM的CCSID系统在UTF-16BE和UTF-16LE之间没有区别,因此我对如何正确转换它一无所知。

如果它是稍后生成的UTF-8格式,则以下内容适用于您。它不是最漂亮,但可以将其投入几个函数中,并且可以正常工作。

Create or replace function unpivothex (in_ varchar(30000))
    returns table (Hex_ char(2), Position_ int)
    return
    with returnstring (ST , POS )
    as 
    (Select substring(STR,1,2), 1
    from table(values in_) as A(STR)
    union all
    Select nullif(substring(STR,POS+2,2),'00'), POS+2
    from returnstring, table(values in_) as A(STR)
    where POS+2 <= length(in_)
    )
    Select ST, POS 
    from returnstring
    ;
Create or replace function converthextostring
   (in_string char(30000))
   returns varchar(30000)
   return
   (select listagg(char(varbinary_format(B.Hex_),1)) within group(order by In_table.Position_)
   from table(unpivothex(upper(in_string))) in_table
   join table(unpivothex(hex(cast('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ' as char(53) CCSID 1208)))) A on In_table.Hex_ = A.Hex_
   join table(unpivothex(hex(cast('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ' as char(53) CCSID 37)))) B on A.Position_ = B.Position_
   );

如果您没有至少使用V7R2 TR6或V7R3 TR2,则为以下版本。

Create or replace function converthextostring
   (in_string char(30000))
   returns varchar(30000)
   return
   (select xmlserialize(
             xmlagg(
               xmltext(cast(char(varbinary_format(B.Hex_),1) as char(1) CCSID 37)) 
             order by In_table.Position_) 
           as varchar(30000))
   from table(unpivothex(upper(in_string))) in_table
   join table(unpivothex(hex(cast('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ' as char(53) CCSID 1208)))) A on In_table.Hex_ = A.Hex_
   join table(unpivothex(hex(cast('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ' as char(53) CCSID 37)))) B on A.Position_ = B.Position_
   );

答案 1 :(得分:0)

我在问您为什么需要这样做...

有充分的理由将十六进制字符串转换回等效的字符...例如,某人向您发送了一个32字节的字符串UUID,而您希望它以16字节的二进制形式返回。

但是没有理由将ONLY FOR BACK-UP ON LEVEL ONE FOR CRANES转换为十六进制。

我怀疑您需要发布一个新问题,询问为什么您一开始就没有获得可读的字符串。

但是,为回答这个问题... IBM i具有一个MI函数Convert Character to Hex (CVTCH),可以从任何ILE语言轻松调用它。您可以将该函数调用包装到用户定义的函数中,以便从SQL使用它。

请注意,您将需要知道十六进制字符串表示的是EBCDIC,ASCII还是Unicode,因为您需要能够告诉系统开始时使用的是什么。从那里,有多种方法可以在编码之间进行转换。

这里有一篇文章,展示了如何从RPG调用MI函数。 Utilizing MI Functions in RPG Programs

利用CCSID关键字增强功能的原型的更现代的自由形式版本可能看起来像

dcl-pr FromHex extproc('cvtch');
  charString char(32767) ccsid(*UTF8) options(*varsize);
  hexString  char(65534) ccsid(*HEX) const options(*varsize);
  hexStringLen int(10) value;
end-pr;

使用上述原型,系统会将返回的字符串视为UTF8(ccsid 1208)。但是我要做的就是告诉系统如何解释返回的字节。如果该字符串实际上是EBCDIC,我将得到垃圾信息。

我认为您甚至可以将cvtch函数直接定义为外部UDF,而无需ILE包装器。我必须去玩...

无视这个想法... cvtch仅具有参数,而没有返回值。使用ILE包装器是将输出参数移至用作UDF的返回值的最佳方法。

答案 2 :(得分:0)

我尝试了以下由Marcin Rudzki在Convert HEX value to CHAR on DB2发布的解决方案,并在我自己的LUW v11的Db2中对其进行了少量修改。

解决方案包括按照Marcin的建议创建一个函数:

CREATE FUNCTION unhex(in VARCHAR(32000) FOR BIT DATA)
RETURNS VARCHAR(32000) 
LANGUAGE SQL
CONTAINS SQL
DETERMINISTIC NO EXTERNAL ACTION
BEGIN ATOMIC
RETURN in;
END

要测试该解决方案,让我们创建一个HEXSAMPLE表,其中的HEXSTRING列已加载HEX序列的字符串表示形式:

INSERT INTO HEXSAMPLE (HEXSTRING) VALUES ('4F4E4C5920464F52204241434B2D5550204F4E204C4556454C204F4E4520464F52204352414E4553')

然后执行以下查询(此处与原始建议不同):

SELECT UNHEX(CAST(HEXTORAW(HEXSTRING) AS VARCHAR(2000) FOR BIT DATA)) as TEXT, HEXSTRING FROM HEXSAMPLE

结果:

 TEXT                                           HEXSTRING
 ----------------------------------------   --------------------------------------------------------------------------------
 ONLY FOR BACK-UP ON LEVEL ONE FOR CRANES   4F4E4C5920464F52204241434B2D5550204F4E204C4556454C204F4E4520464F52204352414E4553

我希望其他人可以找到更直接的解决方案。另外,如果有人可以解释它为什么起作用,那将非常有趣。

答案 3 :(得分:0)

问题是您的原始字符串为ASCII格式(实际上每个字母后都有x'00'字节),因此您必须将其转换为EBCDIC。
以下是仅适用于拉丁大写字母的解决方案:

select cast(translate(replace(mycol, x'00', x'')  
, x'C1C2C3C4C5C6C7C8C9D1D2D3D4D5D6D7D8D9E2E3E4E5E6E7E8E940'  
, x'4142434445464748494A4B4C4D4E4F505152535455565758595A20'
) as varchar(500) ccsid 37)
from mytab;

每个ASCII字符都转换为相应的EBCDIC。
x'00'符号已删除。

答案 4 :(得分:0)

cast (col_name as varchar(2000) ccsid ascii for sbcs data)