【问题标题】:How do I fix "numeric or value error" message?如何修复“数字或值错误”消息?
【发布时间】:2011-11-30 19:59:45
【问题描述】:

我现在整个上午都被这个问题所困扰。我实际上在这里看到了这段代码,并决定在这里将其用于我们的目的。

我遇到的问题是,当我们执行代码时,有时它会将文件从 db 写入文件夹。

其他时候,我们会收到“数字或值错误”

哪位高手可以帮我解决一下吗?

这是我正在使用的代码:

create or replace
PROCEDURE getfile(pfname   VARCHAR2, display_name IN VARCHAR2)
IS
  vblob      BLOB;
  vstart     NUMBER := 1;
  bytelen    NUMBER := 32000;
  len        NUMBER;
  my_vr      RAW(32000);
  x          NUMBER;
  v_name     VARCHAR2(32760);
  lv_str_len NUMBER;
  l_output   utl_file.file_type;
BEGIN
  -- define output directory
  --lv_str_len := Length(pfname);

  --v_name := display_name||upper(substr(pfname,lv_str_len-3,lv_str_len));
  v_name := display_name;

  l_output := utl_file.Fopen('My_DIR', v_name, 'w', 32760);

  -- get length of blob
  SELECT dbms_lob.Getlength(FILENAME)
  INTO   len
  FROM   GENERAL.GUBFILE
  WHERE  gubfile_name = pfname;

  -- dbms_output.put_line('Length: '||len);
  -- save blob length
  x := len;

  -- select blob into variable
  SELECT BLOBVALUE
  INTO   vblob
  FROM   FILES
  WHERE  filename = pfname;

  -- if small enough for a single write
  IF len < 32760 THEN
    -- dbms_output.put_line('Single write ');
    utl_file.Put_raw(l_output, vblob);

    utl_file.Fflush(l_output);
  ELSE -- write in pieces
    -- dbms_output.put_line('multi write '||vstart);
    vstart := 1;

    WHILE vstart < len LOOP
        dbms_lob.READ(vblob, bytelen, vstart, my_vr);

        utl_file.Put_raw(l_output, my_vr);

        utl_file.Fflush(l_output);

        -- set the start position for the next cut
        vstart := vstart + bytelen;

        -- set the end position if less than 32000 bytes
        x := x - bytelen;

        IF x < 32000 THEN
          bytelen := x;
        END IF;
    END LOOP;
  END IF;

  dbms_output.Put_line('End');

  utl_file.Fclose(l_output);
END getfile;

确切的错误是:

ORA-06502:PL/SQL:数字或值错误 ORA-06512: 在 "USER.GETFILE" 第 40 行 ORA-06512: 在第 8 行

【问题讨论】:

    标签: oracle plsql oracle9i


    【解决方案1】:

    错误来自utl_file.put_raw。 buffer参数的最大大小为32767字节。

    您检查了IF len &lt; 32760 THEN,但是,我在您的代码中看不到保证len 变量实际上包含vblob 变量的长度,该变量是put_raw 调用中的缓冲区。

    所以我想vblob 变量的实际长度比 32767 长,这就是错误的原因。

    因此我建议删除这段代码:

      IF len < 32760 THEN
        -- dbms_output.put_line('Single write ');
        utl_file.Put_raw(l_output, vblob);
    
        utl_file.Fflush(l_output);
      ELSE
    

    当然还有END IF;,并且总是选择“写成碎片”分支。

    我现在明白了,你已经根据 Burleson 的例子做了这个,这很好 http://www.dba-oracle.com/t_writing_blob_clob_os_file.htm

    但是你看,与你不同的是,Burleson 从同一个表和同一个字段中获取 len 变量和 vblob 变量。

    -- get length of blob
    SELECT dbms_lob.getlength(productblob)
    INTO len
    FROM products
    WHERE id = product_id;
    
    -- save blob length
    x := len;
    
    -- select blob into variable
    SELECT product_blob
    INTO vblob
    FROM products
    WHERE id = product_id;
    

    编辑

    因此,另一种选择是修复选择以获取长度。这意味着您必须替换此选择:

      -- get length of blob
      SELECT dbms_lob.Getlength(FILENAME)
      INTO   len
      FROM   GENERAL.GUBFILE
      WHERE  gubfile_name = pfname;
    

    用这个:

      -- get length of blob
      SELECT dbms_lob.Getlength(BLOBVALUE)
      INTO   len
      FROM   FILES
      WHERE  filename = pfname;
    

    【讨论】:

    • 狂热的解释!非常感谢。我将 select...filename 更改为 select...blobvalue 并且成功了!你能帮我删除 WHERE 吗?这样,我们可以一次抓取所有文件?
    • @Chidi,感谢您的反馈!如果这个问题已经解决了,那么我严重建议你关闭这个帖子。通过添加新请求来使线程变得混乱的意大利面条显然违反了 SO 原则。如果要将多个 blob 写入文件,则必须打开一个游标并为游标返回的每个文件名/显示名对调用此过程。这里有一个小提示,如何做到这一点,如果还不够,请在新帖子中寻求帮助。 for c in (select filename from FILES) loop getfile(c.filename, c.filename||'.txt'); end loop;
    • 我是否正确假设这会将文件写入 db 所在主机上的文件系统,而不是写入我的客户端运行的本地驱动器?
    • @Adam,你是对的。 utl_file 将在托管数据库的机器上创建文件
    猜你喜欢
    • 2020-11-18
    • 1970-01-01
    • 2021-12-16
    • 1970-01-01
    • 2021-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-07
    相关资源
    最近更新 更多