如何在 Oracle 中获取 CLOB 列的字节大小?

Posted

技术标签:

【中文标题】如何在 Oracle 中获取 CLOB 列的字节大小?【英文标题】:How to get size in bytes of a CLOB column in Oracle? 【发布时间】:2009-11-25 14:17:53 【问题描述】:

如何在 Oracle 中获取 CLOB 列的大小(以字节为单位)?

LENGTH()DBMS_LOB.getLength() 都返回 CLOB 中使用的字符数,但我需要知道使用了多少字节(我正在处理多字节字符集)。

【问题讨论】:

为什么要关心 CLOB 的字节大小? 不是 OP,但在我的情况下,我正在通过数据库链接检索 CLOBS,并且必须将它们切成 4000 字节的块,我想知道我的数据需要多少块。 这太疯狂了,我想把中文 clob 挤进 varchar2 做不到,因为我无法确定大小 【参考方案1】:

经过一番思考,我想出了这个解决方案:

 LENGTHB(TO_CHAR(SUBSTR(<CLOB-Column>,1,4000)))

SUBSTR 仅返回前 4000 个字符(最大字符串大小)

TO_CHARCLOB 转换为 VARCHAR2

LENGTHB 返回字符串使用的字节长度。

【讨论】:

您可以说LENGTHB(TO_CHAR(DBMS_LOB.SUBSTR(&lt;CLOB-Column&gt;,3000,1)))+NVL(LENGTHB(TO_CHAR(DBMS_LOB.SUBSTR(&lt;CLOB-Column&gt;,3000,3001))),0) - 最多可以使用 6000 个字节,但可以无限扩展。如果您正在处理多字节字符集,您需要将子字符串设置为少于 4000 个字符,否则您会得到 ORA-06501 字符串缓冲区太小。另请注意,DBMS_LOB.SUBSTR 与数量和偏移参数的顺序相反。 另见***.com/questions/10331912/…【参考方案2】:

我将我的评论添加为答案,因为它解决了比接受的答案更广泛的案例的原始问题。注意:您仍然必须知道数据的最大长度和多字节字符的大致比例。

如果您的 CLOB 大于 4000 字节,则需要使用 DBMS_LOB.SUBSTR 而不是 SUBSTR。 请注意,amountoffset 参数在 DBMS_LOB.SUBSTR 中是相反的。

接下来,你可能需要一个小于4000的子串,因为这个参数是字符的个数,如果你有多字节字符那么4000个字符将超过4000个bytes 长,您将得到ORA-06502: PL/SQL: numeric or value error: character string buffer too small,因为子字符串结果需要适合具有 4000 字节限制的 VARCHAR2。您可以检索的确切字符数取决于数据中每个字符的平均字节数。

所以我的答案是:

LENGTHB(TO_CHAR(DBMS_LOB.SUBSTR(<CLOB-Column>,3000,1)))
+NVL(LENGTHB(TO_CHAR(DBM‌​S_LOB.SUBSTR(<CLOB-Column>,3000,3001))),0)
+NVL(LENGTHB(TO_CHAR(DBM‌​S_LOB.SUBSTR(<CLOB-Column>,6000,6001))),0)
+...

您可以根据需要添加尽可能多的块来覆盖最长的 CLOB,并根据数据的平均每字符字节数调整块大小。

【讨论】:

查看 TobiK 的回答,了解表示为循环的相同技术,这样您就无需检查是否添加了足够的块来覆盖最大的 CLOB。 所以这个解决方案依靠希望和猜测来避免 ORA-06502 错误?当然有一种强大的方法可以将 CLOB 拆分为 VARCHAR2 大小的块! @PhilHibbs 这对我的目的来说已经足够了,因为我只需要处理法语并且可以对多字节字符的比例做出假设。但我同意这并不令人满意,我很高兴看到更好的答案。【参考方案3】:

对于大于 VARCHAR2 的 CLOB 大小,试试这个:

我们必须将 CLOB 拆分为“与 VARCHAR2 兼容”大小的部分,遍历 CLOB 数据的每个部分,然后汇总所有结果。

declare
   my_sum int;
begin
   for x in ( select COLUMN, ceil(DBMS_LOB.getlength(COLUMN) / 2000) steps from TABLE ) 
   loop
       my_sum := 0;
       for y in 1 .. x.steps
       loop
          my_sum := my_sum + lengthb(dbms_lob.substr( x.COLUMN, 2000, (y-1)*2000+1 ));
          -- some additional output
          dbms_output.put_line('step:' || y );
          dbms_output.put_line('char length:' || DBMS_LOB.getlength(dbms_lob.substr( x.COLUMN, 2000 , (y-1)*2000+1 )));
          dbms_output.put_line('byte length:' || lengthb(dbms_lob.substr( x.COLUMN, 2000, (y-1)*2000+1 )));
          continue;
        end loop;
        dbms_output.put_line('char summary:' || DBMS_LOB.getlength(x.COLUMN));
        dbms_output.put_line('byte summary:' || my_sum);
        continue;
    end loop;
end;
/

【讨论】:

如果您需要在将来执行请求而没有先验知道最大可能的 CLOB 大小的情况下,这比我的回答要好。不过,在这种情况下,我会把它写成一个函数。 运行上述代码时出现此错误:ORA-06502: PL/SQL: numeric or value error ORA-06512: at line 14 ORA-06512: at line 14 06502. 00000 - "PL /SQL: 数值或数值错误%s" 忽略我之前的评论。这是因为我在 CLOB 列中有一些空值。如果我只是在查询中添加“where column is not null”就可以了。【参考方案4】:

NVL(length(clob_col_name),0) 对我有用。

【讨论】:

不,length字符 为单位返回长度,而不是字节。【参考方案5】:

简单的解决方案是将 CLOB 转换为 BLOB,然后请求 BLOB 的长度!

问题在于 Oracle 没有将 CLOB 转换为 BLOB 的函数,但我们可以简单地定义一个函数来执行此操作

create or replace
FUNCTION clob2blob (p_in clob) RETURN blob IS 
    v_blob        blob;
    v_desc_offset PLS_INTEGER := 1;
    v_src_offset  PLS_INTEGER := 1;
    v_lang        PLS_INTEGER := 0;
    v_warning     PLS_INTEGER := 0;  
BEGIN
    dbms_lob.createtemporary(v_blob,TRUE);
    dbms_lob.converttoblob
        ( v_blob
        , p_in
        , dbms_lob.getlength(p_in)
        , v_desc_offset
        , v_src_offset
        , dbms_lob.default_csid
        , v_lang
        , v_warning
        );
    RETURN v_blob;
END;

获取字节数的SQL命令是

SELECT length(clob2blob(fieldname)) as nr_bytes 

SELECT dbms_lob.getlength(clob2blob(fieldname)) as nr_bytes

我在没有使用 Unicode(UTF-8) 的情况下在 Oracle 10g 上对此进行了测试。 但我认为这个解决方案使用 Unicode(UTF-8) Oracle 实例一定是正确的:-)

我想要渲染感谢 Nashev 发布了一个将 clob 转换为 blob How convert CLOB to BLOB in Oracle? 的解决方案以及这篇用德语写的帖子(代码在 PL/SQL 中)13ter.info.blog,它还提供了一个将 blob 转换为的函数呸!

有人可以在 Unicode(UTF-8) CLOB 中测试这 2 个命令,所以我确定这适用于 Unicode 吗?

【讨论】:

【参考方案6】:

使用表名从 dba_lobs 检查 LOB 段名。

select TABLE_NAME,OWNER,COLUMN_NAME,SEGMENT_NAME from dba_lobs where TABLE_NAME='<<TABLE NAME>>';

现在使用段名查找 dba_segments 中使用的字节。

select s.segment_name, s.partition_name, bytes/1048576 "Size (MB)"
from dba_segments s, dba_lobs l
where s.segment_name = l.segment_name
and s.owner = '<< OWNER >> ' order by s.segment_name, s.partition_name;

【讨论】:

【参考方案7】:

它只能工作到 4000 字节,如果 clob 大于 4000 字节,那么我们使用这个

declare
v_clob_size clob;

begin

      v_clob_size:= (DBMS_LOB.getlength(v_clob)) / 1024 / 1024;
      DBMS_OUTPUT.put_line('CLOB Size   ' || v_clob_size);   
end;

select (DBMS_LOB.getlength(your_column_name))/1024/1024 from your_table

【讨论】:

但是 DMBS_LOG.getlength(...) 不是返回字符数而不是字节数吗?

以上是关于如何在 Oracle 中获取 CLOB 列的字节大小?的主要内容,如果未能解决你的问题,请参考以下文章

oracle数据类型

如何使用 oracle sql 命令查找 clob 数据列的特定子部分(实际存储字符)?

JAVA中操作CLOB大对象 ,提示ORA-01704字符串文字太长

oracle如何向空表中添加一个类型为clob的非空列

oracle 某个表的字段里面的值是<clob>是啥意思

php oracle数据库clob和nclob字段