关于sas:将分层Oracle查询转换为DB2查询

Translate hierarchical Oracle query to DB2 query

我主要与SAS和Oracle合作,但对DB2还是一个新手。我面临着需要进行层次化查询以将Clob分为可放入sas的大块的问题。 SAS的字符变量限制为32K,因此我不能正常地将数据集拉入。

我发现了一个古老的stackoverflow问题,它涉及将Clob放入sas数据集中的最佳方法,但是它是用Oracle编写的。
通过SAS从ORACLE DB

导入blob

由于我是DB2的新手,因此这种连接的语法似乎非常不同,所以我希望找到一个可以帮助转换它并解释语法的人。我发现Oracle语法更容易理解。我不确定在DB2中是否使用像这样的CTE递归:https://www.ibm.com/support/knowledgecenter/zh-CN/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查询。

1
2
3
4
5
6
7
8
9
10
11
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,看起来像这样。

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

以为我想要这个结果。我只会一次在id =我正在处理的那一行上执行这一行。

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

感谢您花费任何时间阅读和帮助。


这里是一个解决方案,应该可以在DB2中进行很少的更改(但是请注意,我一点也不了解DB2;我只是使用SQL标准中的Oracle功能,因此应该以相同的方式实现它们-或几乎如此-在DB2中)。

下面,我用您的示例数据创建一个表格;然后,我将展示如何将其分块为最多8个字符的子字符串。尽管字符串很短,但我将列定义为CLOB,并且正在使用CLOB工具。这应该适用于更大的CLOB。

如果需要,可以将块大小和id都设置为绑定参数。在下面的演示中,我对块大小进行了硬编码,并在表中显示了所有ID的结果。如果CLOB为NULL,我会返回一个块(当然是NULL)。

请注意,在查询中触摸CLOB非常昂贵;因此,大多数工作无需触摸CLOB即可完成。我只对它们进行尽可能少的处理。

PREP作品

1
2
3
4
5
6
7
8
9
10
11
12
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;

查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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


另一种选择是在Db2中启用Oracle兼容性,并仅发出分层查询。

此GitHub存储库提供有关DB2中SQL递归的背景信息,包括Oracle样式语法和并排示例(均针对Db2示例数据库进行工作):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 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;