提取表中所有记录的BLOB内容

时间:2018-06-20 17:28:13

标签: oracle plsql

我目前有一张包含150,000条记录的表。每条记录都附有简历。我当前的项目要求将存储在BLOB列中的所有简历提取到文件系统上的文件夹中。

我基于一个示例创建了一个过程,该示例使我可以提取1条记录,但是一旦删除了其中的记录标识符,我就无法弄清楚如何遍历每条记录并提取所有文件。该过程的where子句因错误而失败。

ERROR at line 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "SYS.WRITE_BLOB_TO_FILE", line 17
ORA-06512: at line 1

如果有人对我有什么见解,我将不胜感激。

我在下面使用的程序。

CREATE OR REPLACE PROCEDURE Write_BLOB_To_File
AS
    v_lob_loc      BLOB;
    v_filename     VARCHAR2(255);
    v_buffer       RAW(32767);
    v_buffer_size  BINARY_INTEGER;
    v_amount       BINARY_INTEGER;
    v_offset       NUMBER(38) := 1;
    v_chunksize    INTEGER;
    v_out_file     UTL_FILE.FILE_TYPE;

    BEGIN

        SELECT  cobrokes.subs.resume, cobrokes.subs.filename
        INTO    v_lob_loc, v_filename
        FROM    cobrokes.subs;

        v_chunksize := DBMS_LOB.GETCHUNKSIZE(v_lob_loc);

        IF (v_chunksize < 32767) THEN
            v_buffer_size := v_chunksize;
        ELSE
            v_buffer_size := 32767;
        END IF;

        v_amount := v_buffer_size;

        DBMS_LOB.OPEN(v_lob_loc, DBMS_LOB.LOB_READONLY);

        v_out_file := UTL_FILE.FOPEN(
            location      => 'LOB_DIR', 
            filename      => v_filename, 
            open_mode     => 'wb',
            max_linesize  => 32767);

        WHILE v_amount >= v_buffer_size
        LOOP

          DBMS_LOB.READ(
              lob_loc    => v_lob_loc,
              amount     => v_amount,
              offset     => v_offset,
              buffer     => v_buffer);

          v_offset := v_offset + v_amount;

          UTL_FILE.PUT_RAW (
              file      => v_out_file,
              buffer    => v_buffer,
              autoflush => true);

          UTL_FILE.FFLUSH(file => v_out_file);

        END LOOP;

        UTL_FILE.FFLUSH(file => v_out_file);

        UTL_FILE.FCLOSE(v_out_file);

        DBMS_LOB.CLOSE(v_lob_loc);

    END;
    /

2 个答案:

答案 0 :(得分:1)

错误很简单-您无法将多个行提取到单个对象中。尝试这样:-

lv_b_resume :=blob_obj_handlr();
lv_v_filenm :=char_obj_handlr();

EXECUTE IMMEDIATE ('SELECT  cobrokes.subs.resume, cobrokes.subs.filename
        FROM    cobrokes.subs') BULK COLLECT into lv_b_resume,lv_v_filenm;

然后执行这样的查询

Settings

答案 1 :(得分:0)

设法弄清楚了,我把这个留给需要完成此任务的其他人。

v_filename是表的列,其中包含BLOB列中文件的文件名,而v_pkey是表中的主键列(我知道该列使用最多的ID)。

此脚本的输出将文件名带有文件名的文件保存在pkey-filename结构中,在我的情况下为“ 102-some-file-name.docx”,原因是我们需要能够跟踪将文档返回表中的记录并使用主键只是最简单的方法。

希望这可以帮助需要完成此任务的其他人。

CREATE OR REPLACE PROCEDURE Write_BLOB_To_File
AS
   v_blob        BLOB;
   v_start       NUMBER             := 1;
   v_bytelen     NUMBER             := 32767;
   v_len         NUMBER;
   v_raw         RAW (32767);
   v_x           NUMBER;
   v_output      UTL_FILE.file_type;
   v_filename    VARCHAR2 (255);
   v_pkey    NUMBER;

BEGIN

   FOR i IN (SELECT DBMS_LOB.getlength (RESUME) v_len, FILENAME v_filename,
                    RESUME v_blob, PKEY v_pkey
               FROM COBROKES.SUBS)

   LOOP
      v_output := UTL_FILE.fopen ('LOB_DIR', i.v_pkey || '-' || i.v_filename || chr(0), 'wb', 32767);
      v_x := i.v_len;
      v_start := 1;
      v_bytelen := 32767;

      WHILE v_start < i.v_len AND v_bytelen > 0
      LOOP
         DBMS_LOB.READ (i.v_blob, v_bytelen, v_start, v_raw);
         UTL_FILE.put_raw (v_output, v_raw);
         UTL_FILE.fflush (v_output);
         v_start := v_start + v_bytelen;
         v_x := v_x - v_bytelen;

         IF v_x < 2000
         THEN
            v_bytelen := v_x;
         END IF;
      END LOOP;

      UTL_FILE.fclose (v_output);
   END LOOP;
END Write_BLOB_To_File;
/