有什么方法可以在游标循环中使用函数将值插入 table?

Is there any way to use a function in a cursor for loop to insert value to table?

尝试将函数(填充序列号)放入变量并在游标循环中使用它以将其插入记录的每一行,但错误表示 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;

如果以上是工作代码,它会将值插入空 table。

执行插入操作不需要游标循环。简单的做一个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;

如果您想将函数的输出用作常量并且只使用一次,那么您可能需要一个变量来存储它,并且可以在上面的 select 查询中使用它来代替函数调用.

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, or better still an identity column.

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