Поиск по этому блогу

среда, 19 января 2011 г.

DB2 запросы к blob полям

Задача. В блобе содержится javaArray с полными именами файлов, включая директории (windows). Необходимо вытащить все имена файлов (без директорий) одной строкой и одним sql запросом.


Особенности работы с blob'ми
hex и некоторые другие функции не работают с блобами длиннее 16336
поэтому то, что получаем в рез-те replace приводим cast к блоб cast(... as blob(16336))

Алгоритм запроса
В блобе данные содержатся в таком виде:
                                  
   Объявление массива java мусор \048имя файла\ мусор \048имя файла\
    1. ищем путь файла между символами
    \         (первое вхождение это начало пути, может быть C:\ или \\ (для сетевых, а такие у нас есть) ) 
    и  \048 , если удлинить ключ мы увеличим точность, но потеряем файлы к-е называются 0481 (пример id -1269221399515    имя файла   /04810032.010/ )

or posstr(FILENAMES, blob('\')) = 0 or posstr(FILENAMES, blob('\048')) = 0
   
    2. вырезаем путь получаем строку
   
    3. убираем мусор, получаем список файлов
соответственно
        ,'00BF', 'END') - это признак перевода строки
        ,'74', '/') - это t (в ранних версиях они возможно служили разделителями элементов массива)
        ,'78', '/') - это x (в поздних версиях разделители массива)
        ,'D0', '*') - пробел
        ,'B5', '*') - пусто
        ,'3B', '') - ; (я ее вставляю вместо пути)
        2E - . 5C - \
можно заменить на пробелы или только звездочки или нули, как удобнее будет работать

Сам запрос
select length(FILENAMES) as length,
id,
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
        replace(
varchar(
hex(cast(
   right(
   

    replace(
        FILENAMES,
        substr(FILENAMES,
        posstr(FILENAMES, blob('\'))-1,
        (posstr(FILENAMES, blob('\048')) -  posstr(FILENAMES, blob('\')))
                    )
     , blob(';')
                )
      , length(
    replace(
        FILENAMES,
        substr(FILENAMES,
        posstr(FILENAMES, blob('\'))-1,
        (posstr(FILENAMES, blob('\048'))  -  posstr(FILENAMES, blob('\')))
                    )
     , blob(';')
                )
                        ) - posstr(FILENAMES, blob('\'))
 )
    as blob(16336) ) )
)
        ,'00BF', 'END')
        ,'74', '/')
        ,'78', '/')
        ,'D0', '*')
        ,'B5', '*')
        ,'3B', '')
        ,'5C','/')
        ,'2E','.')
        ,'30','0')
        ,'31','1')
        ,'32','2')
        ,'33','3')
        ,'34','4')
        ,'35','5')
        ,'36','6')
        ,'37','7')
        ,'38','8')
        ,'39','9')       

from loads.LOADS
where
FILENAMES is not null
and posstr(FILENAMES, blob('\')) > 0
and posstr(FILENAMES, blob('\048')) > 0
;

Результат
/04800051.007/0014491/04800051.029/0044491/0480006120*A0.027
Конечно же результат содержит мусор, например данные "*A0", что в реальных проектах может быть критичным, однако можно констатировать, что результата мы таки достигли.

Ограничения запроса
1. то, что мы получаем в результате replace не должно превышать размер 16336 (у нас пока даже блобы не выходят за эти рамки)
2. Наличие "грязи" в запросах, которые содержат список файлов, убирать всю "грязь" не имеет смысла
    так как можно потерять информацию
        массив, который получается
        может выглядеть так
        /04800051.007/0014491/04800051.029/0044491/0480006120*A0.027
        т.е. члены массива разделены слэшами (первого слэша может не быть 04800052.014/)
        нас интересуют только те элементы, которые содержат 048 и точку
       
0480006120*A0.027 - этот файл обозвали не в соответствии с регламентом, его имя 0480006120 D.027       


3. В выборках, поисках по этому блобу нельзя использовать русские символы, так как данные содержатся в юникоде
4. Выборка по ключу имеет определенные ограничения
    если назвать путь \048_ваоаво\048_000\0480000.001 - то мы получим некорректный результат, мусор