Перевести иерархический запрос Oracle в запрос DB2 - PullRequest
0 голосов
/ 22 марта 2019

Я работаю в основном с SAS и Oracle и все еще новичок в DB2. Я столкнулся с необходимостью иерархического запроса для разделения сгустка на куски, которые можно вставить в sas. SAS имеет ограничение 32 КБ для символьных переменных, поэтому я не могу просто вставить набор данных в обычном режиме.

Я нашел старый вопрос о стековом потоке о том, как лучше всего поместить сгусток в набор данных sas, но он написан на Oracle. Импорт BLOB-объектов через SAS из ORACLE DB

Поскольку я новичок в DB2, и синтаксис для этого типа объединения кажется совершенно другим, я надеялся найти кого-то, кто мог бы помочь преобразовать его и объяснить синтаксис. Я считаю, что синтаксис Oracle гораздо проще для понимания. Я не уверен, что в DB2 вы бы использовали рекурсию CTE, такую ​​как https://www.ibm.com/support/knowledgecenter/en/SSEPEK_10.0.0/apsg/src/tpc/db2z_xmprecursivecte.html, или если бы вы использовали иерархические запросы, подобные этой https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/sqlp/rbafyrecursivequeries.htm

Вот запрос Oracle.

SELECT    
      id  
    , level as chunk_id
    , regexp_substr(clob_value, '.{1,32767}', 1, level, 'n') as clob_chunk
FROM (
    SELECT id, clob_value
    FROM schema.table
    WHERE id = 1
)
CONNECT BY LEVEL <= regexp_count(clob_value, '.{1,32767}',1,'n')
order by id, chunk_id;

Таблица содержит два поля id и clob_value и будет выглядеть следующим образом.

ID    CLOB_VALUE
1     really large clob
2     medium clob
3     another large clob

Мысль, что я хотел бы получить этот результат. Я буду делать только одну строку за раз, когда id = какой из строк я обрабатываю.

ID  CHUNK_ID   CLOB
1   1       clob_chunk1of3
1   2       clob_chunk2of3
1   3       clob_chunk3of3

Спасибо, что потратили время на чтение и помощь.

Ответы [ 2 ]

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

Вот решение, которое должно работать в DB2 с небольшими изменениями (но учтите, что я вообще не знаю DB2; я просто использую функции Oracle, которые есть в стандарте SQL, поэтому они должны быть реализованы одинаково - или почти так - в DB2).

Ниже я создаю таблицу с вашими примерами данных; затем я покажу, как разбить его на подстроки длиной не более 8 символов. Хотя строки короткие, я определил столбец как CLOB и использую инструменты CLOB; это должно работать на гораздо больших CLOB.

При необходимости вы можете преобразовать размер чанка и идентификатор в параметры связывания. В моей демонстрации ниже я жестко закодировал размер чанка и показываю результат для всех идентификаторов в таблице. В случае, если CLOB НЕДЕЙСТВИТЕЛЕН, я возвращаю один кусок (который, конечно, НЕДЕЙСТВИТЕЛЕН).

Обратите внимание, что касание CLOB в запросе очень дорого; поэтому большая часть работы выполняется без прикосновения к CLOB. Я работаю над ними как можно меньше.

ПОДГОТОВКА РАБОТЫ

drop table tbl purge;    -- If needed

create table tbl (id number, clob_value clob);

insert into tbl (id, clob_value)
  select 1, 'really large clob'  from dual union all
  select 2, 'medium clob'        from dual union all
  select 3, 'another large clob' from dual union all
  select 4, null                 from dual             -- added to check handling
;

commit;

QUERY

with
  prep(id, len) as (
    select id, dbms_lob.getlength(clob_value)
    from   tbl
  )
,  rec(id, len, ord, pos) as (
    select  id, len, 1, 1
      from  prep
    union all
    select  id, len, ord + 1, pos + 8
      from  rec
      where len >= pos + 8
  )
select   id, ord, dbms_lob.substr(clob_value, 8, pos)
from     tbl inner join rec using (id)
order by id, ord
;

  ID  ORD CHUNK   
---- ---- --------
   1    1 really l
   1    2 arge clo
   1    3 b       
   2    1 medium c
   2    2 lob     
   3    1 another 
   3    2 large cl
   3    3 ob      
   4    1        
0 голосов
/ 22 марта 2019

Другой вариант - включить совместимость Oracle в Db2 и просто выполнить иерархический запрос .

. Этот репозиторий GitHub содержит фоновую информацию о рекурсии SQL.в DB2 , включая синтаксис в стиле Oracle и пример рядом (оба работают с образцом базы данных Db2):

-- both queries are against the SAMPLE database
-- and should return the same result
SELECT LEVEL, CAST(SPACE((LEVEL - 1) * 4) || '/' || DEPTNAME
       AS VARCHAR(40)) AS DEPTNAME
FROM DEPARTMENT
     START WITH DEPTNO = 'A00'
     CONNECT BY NOCYCLE PRIOR DEPTNO = ADMRDEPT;


WITH tdep(level, deptname, deptno) as (
    SELECT 1, CAST( DEPTNAME AS VARCHAR(40)) AS DEPTNAME, deptno
    FROM department 
    WHERE DEPTNO = 'A00'
    UNION ALL
    SELECT t.LEVEL+1, CAST(SPACE(t.LEVEL  * 4) || '/' || d.DEPTNAME
       AS VARCHAR(40)) AS DEPTNAME, d.deptno
    FROM DEPARTMENT d, tdep t
    WHERE d.admrdept=t.deptno and d.deptno<>'A00')
SELECT level, deptname
FROM tdep;
...