有什么方法可以在游标中的函数中进行循环以将值插入表中?

时间:2019-05-05 08:03:55

标签: oracle function for-loop plsql cursor

尝试将一个函数(填充序列号)放置到变量中,并在游标循环中使用该函数将其插入记录的每一行,但是将无效标识符错误地表示给v_refnr变量。 PL/SQL: ORA-00904: "V_REFNR": invalid identifier

我找到的最接近的参考文献是这个[1] Call a function in a cursor for loop

我的函数没有参数。我在游标中所做的select语句(包含其他列)在输出值时没有问题。我继续使用for循环遍历每条记录,然后插入参考号以测试其是否有效。

这是我到目前为止尝试过的代码

Declare
 v_refnr number;
 cursor c_book IS
   --working select statement--
 r_book c_book%ROWTYPE

begin
  v_refnr := get_refnr; <-- function

  for r_book in c_book loop
  insert into some_tbl refnr
  values v_refnr;  
  end loop;
    EXCEPTION
    WHEN OTHERS THEN
    dbms_output.put_line('Error insert record ' || SUBSTR(SQLERRM, 1, 250));
    ROLLBACK;
end;

如果以上是有效代码,它将在空白表中插入值。

2 个答案:

答案 0 :(得分:1)

执行插入操作不需要游标循环。只需执行INSERT INTO SELECT *,它比循环要有效得多。

因此,如果您想每次都调用该函数,请在select中使用它。

BEGIN
  INSERT INTO some_tbl (refnr,col1,col2,col3)
     SELECT get_refnr,col1,col2,col3 from yoursourcetable; 
                                          --Your working select statement
    EXCEPTION
     WHEN OTHERS THEN
    dbms_output.put_line('Error insert record ' || substr(SQLERRM,1, 250));
 ROLLBACK;
END;

如果只想一次使用函数的输出作为常量,则可能需要一个变量来存储它,并且可以在上面的选择查询中使用它来代替函数调用。

答案 1 :(得分:1)

insert ... values的语法是

insert into sometable (col1, col2, col3)
values (value1, value2, value3);

您的代码缺少两组括号。

有一个PL/SQL-only variant,其中的values子句被PL / SQL记录代替了:

insert into sometable (col1, col2, col3)
values plsqlrecord;

这在值表达式中没有括号,但是它必须是PL / SQL记录,通常是sometable%rowtype,而v_refnr不是,因此是错误消息。

此外,Cursor FOR loop结构隐式生成自己的记录,在这种情况下,循环中的r_book,而顶部使用的其他r_book则不使用。因此,固定版本如下所示:

declare
    v_refnr number;

    cursor c_book is
        select col1, col2, col3 from book;
begin
    v_refnr := get_refnr;

    for r_book in c_book loop
        insert into some_tbl (col1, col2, col3)
        values (v_refnr, col2, col3);  
    end loop;
end;

尽管我希望通过移动查询来消除游标声明:

declare
    v_refnr number;
begin
    v_refnr := get_refnr;

    for r_book in (
        select col1, col2, col3 from book
    )
    loop
        insert into some_tbl (col1, col2, col3)
        values (v_refnr, col2, col3);  
    end loop;
end;

我还通过删除when others异常处理程序来改进了错误处理,该异常处理程序没有做任何有用的事情。未处理异常的默认处理是打印带有行号的错误堆栈,并将事务回滚到块的开头,并且尝试自己编写该代码将永远不会像以前那样好,因为会丢失原始的行号和块看起来实际上是成功完成的,更不用说将错误消息截断为250个字符没有任何好处。

这只会留下三个可能的问题:

  1. 您只会在顶部生成一次电话号码,而不会在插入的每一行生成一次电话号码。也许这是有目的的,但如果不是,则应在循环内移动函数调用。

  2. 如果所有get_refnr()都产生一个序列号,那么Oracle已经提供了一种用于执行此操作的方法,称为sequence,或者更佳的是identity column

  3. 如果循环的唯一目的是从select语句中插入行,正如Kaushik Nayak指出的那样,您可以使用insert ... select语法在普通SQL中完成此操作,而无需执行任何循环或变量等,它会更简单,更快。