【问题标题】:Need to Write CLOB file data into ORACLE table with PLSQL需要用PLSQL将CLOB文件数据写入ORACLE表
【发布时间】:2015-03-05 09:16:01
【问题描述】:

我在 clob 字段中有平面文件,平面文件的结构如下所示。和平面文件包含 x 百万条记录。

col1,col2,col3,col4,col5,col6
A,B,C,,F,D
1,A,2,B,B,C

我不能用的传统方式

1-从 excel 中的 clob 或其他东西中获取数据,然后使用 sql-loader 将数据加载到表中。

2-目前我可以使用以下代码打印 clob 文件。

OPEN c_clob;
LOOP
FETCH c_clob INTO c;
EXIT
WHEN c_clob%notfound;
printout(c);

但上面代码中的问题是,如果我在插入语句中使用这个变量,那么由于 CLOB 到 VAR 插入,它会给出错误。

INSERT INTO Table1 VALUES(c);
commit;

ORA-22835: Buffer too small for CLOB to CHAR or BLOB to RAW conversion (actual: 848239, maximum: 4000)

是否有任何其他选项可用于处理来自 clob 字段的巨大平面文件并将其转储到表中。

目前我正在使用以下代码

declare nStartIndex number := 1; nEndIndex number := 1; nLineIndex number := 0; vLine varchar2(2000); cursor c_clob is select char_data from clob_table where seq=1022; c clob; procedure printout (p_clob in out nocopy clob) is offset number := 1; amount number := 32767; amount_last number := 0; len number := dbms_lob.getlength(p_clob); lc_buffer varchar2(32767); line_seq pls_integer := 1; -- For UNIX type file - replace CHR(13) to NULL CR char := chr(13); --CR char := NULL; LF char := chr(10);
nCRLF number; sCRLF varchar2(2); b_finish boolean := true; begin sCRLF := CR || LF; nCRLF := Length(sCRLF); if ( dbms_lob.isopen(p_clob) != 1 ) then dbms_lob.open(p_clob, 0); end if; amount := instr(p_clob, sCRLF, offset); while ( offset < len ) loop -- For without CR/LF on end file If amount < 0 then amount := len - offset + 1; b_finish := false; End If; dbms_lob.read(p_clob, amount, offset, lc_buffer); If b_finish then lc_buffer := SUBSTR(lc_buffer,1,Length(lc_buffer)-1);
End If; if (line_seq-1) > 0 then amount_last := amount_last + amount; offset := offset + amount; else amount_last := amount; offset := amount + nCRLF; end if; amount := instr(p_clob, sCRLF, offset); amount := amount - amount_last; dbms_output.put_line('Line #'||line_seq||': '||lc_buffer); line_seq := line_seq + 1; end loop; if ( dbms_lob.isopen(p_clob) = 1 ) then dbms_lob.close(p_clob); end if; exception when others then dbms_output.put_line('Error : '||sqlerrm); end printout; begin open c_clob; loop fetch c_clob into c; exit when c_clob%notfound; printout(c); end loop; close c_clob; end;

这里的printout(c); 行(代码中的倒数第四行)逐行显示 clob 数据,直到缓冲区溢出。

预期结果:要从 clob 平面文件中读取数据并将行插入到表列中,这就是我想要实现的。 Constraints is Flat-Files 包含数百万条记录

【问题讨论】:

  • 不确定我是否理解...您有一个包含 CSV 数据的 CLOB,并且您想将其转换为另一个表中的单独列?或者只是将整个 CLOB 复制到另一个表? Table1 中的列是什么数据类型,c_clob 光标后面的查询是什么?
  • 是的,Clob 包含 csv 文件。我想将其转换为另一个表中的单独列。 CURSOR c_clob IS SELECT char_data FROM table ;
  • 然后您需要逐行读取 CLOB(请参阅the dbms_lob package),然后根据逗号分隔符将每一行拆分为标记。这两个部分都有很多例子,你只需要把它们放在一起。
  • use a library,而不是自己创建。
  • @AlexPoole 您能否提供有关 DBMS_LOB 使用和将行拆分为令牌的任何参考。我找不到这样的工作示例。

标签: sql database plsql oracle11g


【解决方案1】:

我正在使用类似的东西

...
select * into ifile from clob_table where ...;
file_length  := dbms_lob.getlength (ifile.char_data);
p_start :=1;
while p_start<>0 loop
    end_pos := dbms_lob.instr (ifile.char_data, chr (10), p_start);
    if end_pos > 0 then
        strRow := dbms_lob.substr(ifile.char_data, least (end_pos - p_start, 240), p_start),chr (13)||chr (10);
        p_start := end_pos + 1;
        tabRow := strRow2tabRow(strRow);
    else
        strRow := dbms_lob.substr (ifile.char_data, file_length - p_start + 1,  p_start);
        p_start := 0;
        tabRow := strRow2tabRow(strRow);
    end if;

insert into myTable values tabRow;
end loop;
...

和功能

function strRow2tabRow(strRow varchar2) return myTable%rowtype is
    tabRow myTable%rowtype;
begin
    tabRow.col1:=valueIncolumn(strRow,1);
    tabRow.col2:=valueIncolumn(strRow,2);
    ...
    /*or maybe this may be better for you
    select * into tabRow from (
        select rownum rn, regexp_substr(strRow,'[^,]+', 1, level) hdn from dual connect by regexp_substr(strRow, '[^,]+', 1, level) is not null 
        ) pivot (max(hdn) for rn in (1, 2, ...));
    */      
    return tabRow;
exception when others then
    return tabRow;
end; 

function valueIncolumn(strRow varchar2, pos in number) return varchar2 is
    ret varchar2(1024);
begin
    select hdn into ret from (
        select rownum rn, regexp_substr(strRow,'[^,]+', 1, level) hdn from dual connect by regexp_substr(strRow, '[^,]+', 1, level) is not null 
    ) where rownum=pos;
    return ret;
exception when others then 
    return null;
end;     

希望对你有帮助

【讨论】:

  • 我们不能处理来自 PLSQL 的 >32K 数据...在 PLSQL 中应该有一种方法...上述方法失败了 :(.. 感谢您的所有帮助..跨度>
  • @Alex 还有其他解决方案吗??
猜你喜欢
  • 2018-10-29
  • 1970-01-01
  • 1970-01-01
  • 2017-04-02
  • 2017-07-13
  • 1970-01-01
  • 1970-01-01
  • 2021-07-16
  • 1970-01-01
相关资源
最近更新 更多