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;