Oracle SQL: как добавить условие IF внутри FORALL LOOP - PullRequest
0 голосов
/ 13 мая 2018

Я пытаюсь объединить таблицу в 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 ]

0 голосов
/ 13 мая 2018

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 ...

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

0 голосов
/ 14 мая 2018

Спасибо за ваш ответ. Можете ли вы добавить пример кода для удаления записей с нулевым счетом из коллекции 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;
0 голосов
/ 13 мая 2018

Оператор 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 с ним.

...