Oracle CLOB列和LAG

时间:2018-11-16 10:07:54

标签: oracle oracle11g

当我尝试在LAG列上使用CLOB函数时遇到问题。

所以我们假设我们有一张桌子

create table test (
    id number primary key, 
    not_clob varchar2(255),
    this_is_clob clob
);

insert into test values (1, 'test1', to_clob('clob1'));
insert into test values (2, 'test2', to_clob('clob2'));

DECLARE
x CLOB := 'C';
BEGIN

 FOR i in 1..32767
 LOOP
  x := x||'C';
 END LOOP;

 INSERT INTO test(id,not_clob,this_is_clob) values(3,'test3',x);

END;
/

commit;

现在让我们使用非Clob列进行选择

select id, lag(not_clob) over (order by id) from test;

它能按预期运行,但是当我尝试使用clob列

select id, lag(this_is_clob) over (order by id) from test;

我知道

ORA-00932: inconsistent datatypes: expected - got CLOB
00932. 00000 -  "inconsistent datatypes: expected %s got %s"
*Cause:    
*Action:
Error at Line: 1 Column: 16

您能告诉我该问题的解决方法是什么,因为我对此一无所获。

3 个答案:

答案 0 :(得分:1)

使用CLOBs时某些功能可能无法在SQL中正常工作(例如DISTINCTORDER BY GROUP BY等。看起来LAG也是其中之一其中,但我在文档中找不到任何地方。

如果CLOB列中的值始终少于4000个字符,则可以使用TO_CHAR

select id, lag( TO_CHAR(this_is_clob)) over (order by id) from test;

OR

将其转换为等效的SELF JOIN(可能不如LAG高效)

SELECT a.id,
       b.this_is_clob AS lagging
FROM test a
LEFT JOIN test b ON b.id < a.id;

Demo

答案 1 :(得分:1)

文档说任何分析函数的参数可以是任何数据类型,但似乎不支持不受限制的CLOB。

但是,有一种解决方法:

select id, lag(dbms_lob.substr(this_is_clob, 4000, 1)) over (order by id) 
from test;

这不是整个CLOB,但在很多情况下4k应该足够了。

  

我仍然想知道解决问题的正确方法是什么

是否可以选择升级到12c?问题与CLOB无关,这是事实,Oracle对SQL中的字符串严格限制为4000个字符。在12c中,我们可以选择使用扩展的数据类型(前提是我们可以说服DBA将其打开!)。 Find out more.

答案 2 :(得分:0)

我知道这是一个老问题,但是我想我找到了一个答案,该答案消除了限制CLOB长度的需要,并希望共享它。利用CTE和递归子查询,我们可以使用CLOB列复制滞后功能。

首先,让我们看一下我的“原始”查询:

WITH TEST_TABLE AS
(
 SELECT LEVEL ORDER_BY_COL,
        TO_CLOB(LEVEL) AS CLOB_COL
 FROM DUAL
 CONNECT BY LEVEL <= 10
)
SELECT tt.order_by_col,
       tt.clob_col,
       LAG(tt.clob_col) OVER (ORDER BY tt.order_by_col)
FROM test_table tt;

按预期,出现以下错误:

ORA-00932:数据类型不一致:预期-获得CLOB

现在,让我们看一下修改后的查询:

WITH TEST_TABLE AS
(
 SELECT LEVEL ORDER_BY_COL,
        TO_CLOB(LEVEL) AS CLOB_COL
 FROM DUAL
 CONNECT BY LEVEL <= 10
),
initial_pull AS
(
  SELECT tt.order_by_col,
         LAG(tt.order_by_col) OVER (ORDER BY tt.order_by_col) AS PREV_ROW,
         tt.clob_col
  FROM test_table tt
),
recursive_subquery (order_by_col, prev_row, clob_col, prev_clob_col) AS
(
  SELECT ip.order_by_col, ip.prev_row, ip.clob_col, NULL
  FROM initial_pull ip
  WHERE ip.prev_row IS NULL
  UNION ALL
  SELECT ip.order_by_col, ip.prev_row, ip.clob_col, rs.clob_col
  FROM initial_pull ip
  INNER JOIN recursive_subquery rs ON ip.prev_row = rs.order_by_col
)
SELECT rs.order_by_col, rs.clob_col, rs.prev_clob_col
FROM recursive_subquery rs;

这就是它的工作原理。

  1. 我创建了TEST_TABLE,这实际上仅用于示例,因为您应该已经将该表放在架构中的某个位置。
  2. 我创建了要提取的数据的CTE,并在表的主键(或唯一列)上加上了LAG函数,其分区和排序方式与原始查询中的方式相同。
  3. 使用初始行作为根,并在滞后列上逐行降序创建递归子查询。从当前行返回CLOB列,并从其父行返回CLOB列。