Oracle SQL: как добавить условие IF внутри FORALL LOOP

Я пытаюсь объединить таблицу в emp1, если select_count не равен 0. Но я не мог добавить оператор select и if внутри цикла FORALL. Может ли кто-нибудь помочь мне достичь этого? Благодарю.

FORALL i IN 1 .. v_emp.LAST
    select count(emp_id) into select_count from emp where emp_id=v_emp(i).emp_id;
    IF select_count <> 0 THEN 
       MERGE INTO emp1 e1 using dual ON(a.id=b.id)
       WHEN MATCHED
         //Update statement
       WHEN NOT MATCHED 
         //Insert statement
    END IF;

Приведенный выше код ошибки выдает сообщение об ошибке:

PLS-00201: Идентификатор "I" должен быть объявлен.

3 ответа

FORALL категорически не является циклической конструкцией. Это атомарное утверждение, так что есть способ ввести условие в него.

Кажется ненужным объединять FORALL с MERGE. MERGE - это уже заданная операция, которая также предоставляет условные выражения. Поэтому, возможно, все, что вам нужно сделать, - это изменить свою реализацию, чтобы исключить предложение USING.

Вы не описали всю логику, которую пытаетесь реализовать, поэтому предположение следующее: вам нужно преобразовать ее в соответствии со своими потребностями.

 merge into emp1 
 using ( select * from table ( v_emp ) t
         where t.emp_id not in ( select e.emp_id 
                                 from emp e )
      ) q
 on (q.emp_id = emp1.emp_id)
 when not matched then 
      insert ...
 when matched then
      update ...

Если это не решит вашу проблему, отредактируйте ваш вопрос, чтобы объяснить больше о вашем сценарии и бизнес-логике, которую вы пытаетесь реализовать.

Oracle PL/SQL FORALL оператор может охватывать только один оператор SQL (без PL/SQL), поскольку это в основном предписывает механизму Oracle SQL выполнять массовую операцию, а механизм SQL не может выполнять блоки PL / SQL.

То, что вы, кажется, хотите сделать, это FOR петля. Что-то вроде этого:

FOR i IN 1 .. v_emp.LAST
LOOP
    select count(emp_id) into select_count from emp where emp_id=v_emp(i).emp_id;
    IF select_count <> 0 THEN 
       MERGE INTO emp1 e1 using dual ON(a.id=b.id)
       WHEN MATCHED
         //Update statement
       WHEN NOT MATCHED 
         //Insert statement
    END IF;
END LOOP;

Если вы все еще хотите MERGE быть исполненным навалом, через FORALL, затем сначала используйте цикл, чтобы вычислить счетчики, затем удалите записи с нулевым счетом из v_emp коллекция, так что вы можете использовать FORALL с этим.

Спасибо за ваш ответ. Можете ли вы добавить пример кода, чтобы удалить записи с нулевым счетом из коллекции v_emp?

Выбирая из ваших комментариев, вы должны выбирать только те записи, которые находятся на первом месте в вашем запросе, где число не равно нулю, а не проверять их на более позднем этапе. Увидеть ниже.

CREATE TABLE emp(emp_NM VARCHAR2(10),
                  emp_id NUMBER,
                  sal NUMBER);
/
INSERT INTO emp VALUES ('X',1,100);                  
INSERT INTO emp VALUES ('A',2,200);
INSERT INTO emp VALUES('B',3,300);
INSERT INTO emp values ('C',4,400);
/
Select * from emp;
/

CREATE OR REPLACE TYPE ep_id IS TABLE OF NUMBER;

/

DECLARE
Type v_emp IS  TABLE OF NUMBER INDEX BY pls_integer;
  emp_var v_emp;

  --Declared a table having emp_id as in your case where you try to get this in a collection v_emp.
  v_ep_id ep_id:=ep_id(1,2,4,5,6);
BEGIN
  ---Query to select only those records whose count is greater than 0.
  SELECT COUNT(emp_id) 
  bulk collect  INTO emp_var
  FROM emp
  --WHERE emp_id IN  (SELECT * FROM TABLE(v_ep_id) ) --< You can use this as well.
  WHERE emp_id MEMBER OF v_ep_id
  GROUP BY emp_id, sal, emp_nm
  HAVING COUNT(emp_id) > 0 ;

  --Here you directly do the merge of the selected records which are not Zero
  FORALL i IN 1 .. emp_var.Count
  MERGE INTO emp1 e1 using dual ON(a.id=b.id)
  WHEN MATCHED
  //Update statement
  WHEN NOT MATCHED
  //Insert statement
  END IF; 

 Exception
 WHEN others then
 raise_application_error(-20001,'Error');
END;
Другие вопросы по тегам