Как привести шестнадцатеричную строку данных в строку db2 sql - PullRequest
0 голосов
/ 15 марта 2019

Как бы вы расшифровали шестнадцатеричную строку, чтобы получить значение в текстовом формате с помощью оператора select?

Например, мои данные в шестнадцатеричном формате:

4f004e004c005900200046004f00520020004200410043004b002d005500500020004f004e0020004c004500560045004c0020004f004e004500200046004f00520020004300520041004e004500530020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020000000

Я хочу декодировать его, чтобы получить строковое значение с помощью оператора select. Значение выше "ТОЛЬКО ДЛЯ РЕЗЕРВНОГО КОПИРОВАНИЯ НА ОДНОМ УРОВНЕ ДЛЯ КРАНОВ"

я попробовал:

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

Приведенный выше sql возвращает точно такую ​​же шестнадцатеричную строку, а не декодированную текстовую строку «ТОЛЬКО ДЛЯ РЕЗЕРВНОГО КОПИРОВАНИЯ НА УРОВНЕ ОДИН ДЛЯ КРАНОВ», что я ожидал.

Возможно ли это сделать с помощью актеров? Если это так, какой будет синтаксис?

Моя проблема в том, что система хранит текстовые данные в поле большого двоичного объекта, и я хочу использовать оператор select, чтобы увидеть, какие текстовые данные находятся в поле большого двоичного объекта.

Db: Db2 на Ibm

Edit:

Мне удалось преобразовать строку в шестнадцатеричное значение, используя:

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

Это дает мне строку в шестнадцатеричном виде:

4F4E4C5920464F52204241434B2D5550204F4E204C4556454C204F4E4520464F52204352414E4553

Теперь как-то мне нужно сделать обратное и получить значение.

Спасибо.

Редактировать

Используя ответ Даниэля Лемы, я попытался использовать функцию unhex, но мой результат был:

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

Это как-то связано с CSSID? Или как мне превратить вышеперечисленное в читаемую строку?

Это определение поля таблицы, если оно поможет полю с моими данными в GDTXFT BLOB:

enter image description here

Ответы [ 4 ]

1 голос
/ 18 марта 2019

Мне удалось взять вашу сокращенную шестнадцатеричную строку и преобразовать ее в действительную строку EBCDIC. Проблема, с которой я столкнулся, заключается в том, что исходный шестнадцатеричный код, который вы получаете, поставляется в формате UTF-16LE (Спасибо, Том Блоджет). Система CCSID от IBM не проводит различий между 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_
   );
0 голосов
/ 15 марта 2019

Я попробовал следующее решение, которое я нашел опубликованным Марсином Рудзки на Преобразование значения HEX в CHAR в DB2 , протестировано в моем собственном Db2 для LUW v11 с небольшой модификацией.

решение заключается в создании функции, как предложил Марцин:

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

Я надеюсь, что кто-то еще сможет найти более прямое решение. Также, если кто-то может объяснить, почему это работает, это будет очень интересно.

0 голосов
/ 18 марта 2019

Проблема в том, что ваша исходная строка имеет формат 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 'символы удаляются.

0 голосов
/ 15 марта 2019

Я спрашиваю, зачем вам это нужно ...

Есть веские причины для преобразования шестнадцатеричной строки обратно в ее символьный эквивалент ... например, кто-то отправляет вам 32-байтовую строку UUID, и вы хотите, чтобы она вернулась, если это 16-байтовая двоичная форма.

Но нет никаких оснований ONLY FOR BACK-UP ON LEVEL ONE FOR CRANES должен был быть преобразован в гекс.

Я подозреваю, что вам нужно опубликовать новый вопрос, спрашивающий, почему вы не получаете удобочитаемые строки.

Однако, в ответ на этот вопрос ... В IBM i есть функция MI Преобразование символа в шестнадцатеричное (CVTCH) , которое легко вызывается из любого языка ILE. Вы можете обернуть этот вызов функции в пользовательскую функцию, чтобы использовать ее из SQL.

Обратите внимание, что вам нужно знать, что представляет собой шестнадцатеричная строка, EBCDIC, ASCII или Unicode, потому что вы должны быть в состоянии рассказать системе, с чего вы начали. Оттуда есть способы преобразования между кодированием.

Вот статья, в которой показано, как вызвать функцию MI из RPG. Использование функций MI в программах RPG

Более современная версия прототипа в свободной форме, в которой используются усовершенствования ключевого слова 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.

...