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

Oracle 提取表中所有记录的BLOB内容,oracle,plsql,Oracle,Plsql,我目前有一个超过150000条记录的表。每份记录都附有一份简历。我当前的项目要求我将BLOB列中存储的所有简历提取到文件系统上的一个文件夹中 我根据我发现的一个示例创建了一个过程,该示例允许我提取一条记录,但我不知道如何让它在每个记录中循环并提取所有文件,一旦我删除where子句中的记录标识符,该过程就会因错误而失败 ERROR at line 1: ORA-01422: exact fetch returns more than requested number of rows ORA-065

我目前有一个超过150000条记录的表。每份记录都附有一份简历。我当前的项目要求我将BLOB列中存储的所有简历提取到文件系统上的一个文件夹中

我根据我发现的一个示例创建了一个过程,该示例允许我提取一条记录,但我不知道如何让它在每个记录中循环并提取所有文件,一旦我删除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;
    /

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

    create or replace type blob_obj_handlr is table of BLOB;
    /
    create or replace type char_obj_handlr is table of varchar2(100);
    /
然后像这样执行查询

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;

我设法解决了这个问题,我将把这个留给其他需要完成这个任务的人

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;
/
v_filename是表的列,其中包含BLOB列中文件的文件名,v_pkey是表中的主键列,我知道该列最常用ID

这个脚本的输出将文件名保存在pkey filename结构中,在我的例子中是“102 some file name.docx”,原因是我们需要bable将文档追溯到表中的记录,使用主键是最简单的方法

希望这能帮助其他需要完成这项工作的人

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;
/

对不起,这不是我的强项,我该如何将其应用到我现有的程序中?