Есть ли способ использовать функцию в курсоре для цикла, чтобы вставить значение в таблицу? - PullRequest
0 голосов
/ 05 мая 2019

Попробуйте поместить функцию (которая заполняет порядковый номер) в переменную и использовать ее в цикле курсора, чтобы вставить ее в каждую строку записи, но ошибка указала недопустимый идентификатор переменной v_refnr.PL/SQL: ORA-00904: "V_REFNR": invalid identifier.

Ближайшая ссылка, которую я нашел, это [1] Вызов функции в курсоре для цикла

Моя функция не имеет параметров.Оператор выбора (содержит другие столбцы), который я сделал в курсоре, без проблем выводит значение.Я продолжаю использовать цикл 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 ]

1 голос
/ 06 мая 2019

Синтаксис insert ... values:

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

В вашем коде отсутствуют оба набора скобок.

Существует вариант PL / SQL-only вкоторый предложение values заменяется записью PL / SQL:

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

У него нет скобок вокруг выражения значений, но это должна быть запись PL / SQL, обычно sometable%rowtype,который v_refnr не является, следовательно, сообщение об ошибке.

Кроме того, конструкция цикла *1017* Cursor FOR неявно генерирует свою собственную запись, в данном случае 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 уже предоставляет метод для выполнениякоторый называется последовательность , или, что еще лучше, столбец идентификаторов .

  3. Если единственной целью цикла является вставка строк из вашегоselect, как указывал Каушик Наяк, вы можете сделать это в обычном SQL, используя синтаксис insert ... select без необходимости использования циклов, переменных и т. Д., И это будет проще и быстрее.

1 голос
/ 05 мая 2019

Вам не нужен цикл курсора для выполнения операции вставки. Просто сделайте 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 вместо вызова функции.

...