【问题标题】:Oracle SQL : How add IF condition inside FORALL LOOPOracle SQL:如何在 FORALL LOOP 中添加 IF 条件
【发布时间】:2019-10-11 14:15:01
【问题描述】:

如果 select_count 不等于 0,我正在尝试将表合并到 emp1。但我无法在 FORALL 循环中添加 select 和 if 语句。谁能帮我实现这一目标?谢谢。

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”。

【问题讨论】:

    标签: sql oracle plsql bulk-operations


    【解决方案1】:

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

    如果这不能解决您的问题,请编辑您的问题以详细说明您的方案和您尝试实施的业务逻辑。

    【讨论】:

      【解决方案2】:

      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;
      

      如果您仍希望通过FORALL 批量执行MERGE,则首先使用循环来计算计数,然后从v_emp 集合中删除计数为零的条目,然后您可以使用FORALL

      【讨论】:

      • 感谢您的回答。您能否添加示例代码以从 v_emp 集合中删除计数为零的条目?
      【解决方案3】:

      感谢您的回答。您能否添加示例代码以删除 v_emp 集合中计数为零的条目?

      从您的 cmets 中选择,您应该只选择查询中计数不为零的那些记录,而不是在稍后阶段检查它。见下文。

      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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-21
        • 1970-01-01
        • 1970-01-01
        • 2016-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多