You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle:不转换为CLOB如何移除BLOB中的无效字符?

移除BLOB中无意义0值字符的Oracle解决方案

问题背景

现有Oracle查询用于将BLOB转换为CLOB,但转换后结果包含无意义的0值字符:

WITH FUNCTION GETCONTENTS(BLOB_IN IN BLOB) RETURN CLOB IS
    CLOBOUT CLOB; CLOBDLT CLOB; LDESTOFF NUMBER := 1; LSOUROFF NUMBER := 1; LLANGOFF NUMBER := DBMS_LOB.DEFAULT_LANG_CTX; LWARNING NUMBER;
    BEGIN
        DBMS_LOB.CREATETEMPORARY(CLOBOUT, TRUE);
        DBMS_LOB.CONVERTTOCLOB(CLOBOUT, BLOB_IN, DBMS_LOB.LOBMAXSIZE, LDESTOFF, LSOUROFF, NLS_CHARSET_ID('WE8ISO8859P1'), LLANGOFF, LWARNING);
        RETURN CLOBOUT;
    END;
SELECT DUMP(DBMS_LOB.SUBSTR(GETCONTENTS(GDTXFT), 50, 1)) FROM PRODDTA.F00165
    WHERE GDOBNM = 'GT4101' AND GDTXKY = 22;

尝试用TRANSLATE移除0值时触发ORA-00905错误,错误脚本如下:

WITH FUNCTION GETCONTENTS(BLOB_IN IN BLOB) RETURN CLOB IS
    CLOBOUT CLOB; CLOBDLT CLOB; LDESTOFF NUMBER := 1; LSOUROFF NUMBER := 1; LLANGOFF NUMBER := DBMS_LOB.DEFAULT_LANG_CTX; LWARNING NUMBER;
    BEGIN
        DBMS_LOB.CREATETEMPORARY(CLOBOUT, TRUE);
        DBMS_LOB.CONVERTTOCLOB(CLOBOUT, BLOB_IN, DBMS_LOB.LOBMAXSIZE, LDESTOFF, LSOUROFF, NLS_CHARSET_ID('WE8ISO8859P1'), LLANGOFF, LWARNING);
        SELECT TRANSLATE(CLOUBOUT, '', '') INTO CLOBOUT FROM DUAL;
    RETURN CLOBOUT;
END;
SELECT DUMP(DBMS_LOB.SUBSTR(GETCONTENTS(GDTXFT), 50, 1)) FROM PRODDTA.F00165
    WHERE GDOBNM = 'GT4101' AND GDTXKY = 22;

错误原因分析

  • 变量名拼写错误:CLOUBOUT应为CLOBOUT
  • TRANSLATE函数用法错误:该函数要求至少3个参数,TRANSLATE(CLOBOUT, '', '')不符合语法,需明确指定要移除的目标字符(即chr(0))

解决方案

方案1:在BLOB阶段直接过滤0值字符

转换为CLOB前先处理BLOB,移除所有对应0值的字节(WE8ISO8859P1编码中chr(0)对应字节0x00):

WITH FUNCTION GETCONTENTS(BLOB_IN IN BLOB) RETURN CLOB IS
    CLEAN_BLOB BLOB;
    CLOBOUT CLOB;
    LDESTOFF NUMBER := 1;
    LSOUROFF NUMBER := 1;
    LLANGOFF NUMBER := DBMS_LOB.DEFAULT_LANG_CTX;
    LWARNING NUMBER;
    BLOB_LEN NUMBER;
    BUFFER RAW(32767);
    POS NUMBER := 1;
BEGIN
    -- 初始化临时BLOB存储清理后的数据
    DBMS_LOB.CREATETEMPORARY(CLEAN_BLOB, TRUE);
    
    BLOB_LEN := DBMS_LOB.GETLENGTH(BLOB_IN);
    
    -- 遍历BLOB,过滤掉0x00字节
    WHILE POS <= BLOB_LEN LOOP
        DBMS_LOB.READ(BLOB_IN, LEAST(32767, BLOB_LEN - POS + 1), POS, BUFFER);
        -- 移除缓冲区中的0x00字节
        BUFFER := REPLACE(BUFFER, UTL_RAW.CAST_TO_RAW(CHR(0)), NULL);
        -- 将清理后的缓冲区写入临时BLOB
        DBMS_LOB.WRITEAPPEND(CLEAN_BLOB, UTL_RAW.LENGTH(BUFFER), BUFFER);
        POS := POS + 32767;
    END LOOP;
    
    -- 将清理后的BLOB转换为CLOB
    DBMS_LOB.CREATETEMPORARY(CLOBOUT, TRUE);
    DBMS_LOB.CONVERTTOCLOB(CLOBOUT, CLEAN_BLOB, DBMS_LOB.LOBMAXSIZE, LDESTOFF, LSOUROFF, NLS_CHARSET_ID('WE8ISO8859P1'), LLANGOFF, LWARNING);
    
    -- 释放临时BLOB资源
    DBMS_LOB.FREETEMPORARY(CLEAN_BLOB);
    
    RETURN CLOBOUT;
END;
SELECT DUMP(DBMS_LOB.SUBSTR(GETCONTENTS(GDTXFT), 50, 1)) FROM PRODDTA.F00165
WHERE GDOBNM = 'GT4101' AND GDTXKY = 22;

方案2:修正TRANSLATE用法在CLOB阶段移除0值

如果更倾向于转换后处理,修正TRANSLATE语法并修复变量拼写错误:

WITH FUNCTION GETCONTENTS(BLOB_IN IN BLOB) RETURN CLOB IS
    CLOBOUT CLOB;
    LDESTOFF NUMBER := 1;
    LSOUROFF NUMBER := 1;
    LLANGOFF NUMBER := DBMS_LOB.DEFAULT_LANG_CTX;
    LWARNING NUMBER;
BEGIN
    DBMS_LOB.CREATETEMPORARY(CLOBOUT, TRUE);
    DBMS_LOB.CONVERTTOCLOB(CLOBOUT, BLOB_IN, DBMS_LOB.LOBMAXSIZE, LDESTOFF, LSOUROFF, NLS_CHARSET_ID('WE8ISO8859P1'), LLANGOFF, LWARNING);
    
    -- 移除CLOB中的chr(0)字符,直接赋值无需SELECT FROM DUAL
    CLOBOUT := TRANSLATE(CLOBOUT, CHR(0) || CLOBOUT, CLOBOUT);
    
    RETURN CLOBOUT;
END;
SELECT DUMP(DBMS_LOB.SUBSTR(GETCONTENTS(GDTXFT), 50, 1)) FROM PRODDTA.F00165
WHERE GDOBNM = 'GT4101' AND GDTXKY = 22;

说明:TRANSLATE(CLOBOUT, CHR(0) || CLOBOUT, CLOBOUT)通过将chr(0)映射为空字符,实现移除所有0值字符的效果。

内容的提问来源于stack exchange,提问作者Felipe Vidal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 06:25:24