加入收藏 | 设为首页 | 会员中心 | 我要投稿 衡阳站长网 (https://www.0734zz.cn/)- 数据集成、设备管理、备份、数据加密、智能搜索!
当前位置: 首页 > 站长百科 > 正文

oracle – 在plsql中使用for循环更新

发布时间:2021-03-16 04:16:37 所属栏目:站长百科 来源:网络整理
导读:我有更新问题并插入下面的列.请告知此事. 这是输入 depnto extra comm----------------------------20 300 NULL20 300 40020 NULL NULL20 500 NULL 这是预期的产出 depnto Extra comm---------------------20 300 30020 300 40020 NULL NULL 20 500 500 我需

我有更新问题并插入下面的列.请告知此事.

这是输入

depnto   extra    comm
----------------------------
20       300      NULL
20       300      400
20       NULL     NULL
20       500      NULL

这是预期的产出

depnto  Extra    comm
---------------------
20      300      300
20      300      400
20      NULL     NULL           
20      500      500

我需要在以下条件下使用额外列更新comm列.

>如果comm为null,则将额外值更新为comm.
>如果comm不为null,则无需更新,
>如果两者都为null,则保留为null,
>如果comm列有一个值,则无需覆盖.

我的节目如下.即使我需要跟踪哪些行已更新以及哪个值在另一个表中.

PROCEDURE (dept_id )
AS
BEGIN
   FOR r IN (SELECT *
               FROM emp
              WHERE comm IS NULL AND extra IS NOT NULL AND deptno = dept_id)
   LOOP
      UPDATE emp
         SET comm = extra
       WHERE comm IS NULL AND extra IS NOT NULL AND deptno = dept_id;



      INSERT INTO changed_comm (deptno,oldval,newval)
           VALUES (dept_id,r.comm,r.extra);
   END LOOP;
EXCEPTION
   WHEN NO_DATA_FOUND
   THEN
      NULL;
END;

请在上面提供一些意见.它没有正确插入.

解决方法

你不需要FOR LOOP,只需要一个UPDATE即可完成工作:

UPDATE emp
  SET comm = extra
WHERE comm IS NULL AND extra IS NOT NULL;

这是一个演示:http://www.sqlfiddle.com/#!4/aacc3/1

—编辑—-
我没有注意到,在预期的输出deptno 10更新为20,更新deptno需要另一个查询:

UPDATE emp
   SET deptno = 20
WHERE deptno = 10;

—-编辑—–
如果要将更改的值插入另一个表,请尝试使用RETURNING..BULK COLLECT和FORALL的过程:

CREATE OR REPLACE PROCEDURE pro_cedure( p_dept_id number  ) 
IS
      TYPE changed_table_type IS TABLE OF changed%ROWTYPE;
      changed_buff changed_table_type;
BEGIN
      SELECT deptno,comm,extra BULK COLLECT INTO changed_buff
      FROM emp
      WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id
      FOR UPDATE;
      UPDATE emp
      SET comm = extra
      WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id;
      FORALL i IN 1 .. changed_buff.count
        INSERT INTO changed VALUES changed_buff( i );
END;
/

如果您不打算在一次调用中处理大量记录(超过1000 …或最多几千),则该过程应该有效.如果一个dept_id可以包含一万或更多行,那么这个过程可能会很慢,因为它会消耗大量的PGA内存.在这种情况下,需要另一种以块的形式进行批量收集的方法.

– 编辑—如何存储序列值——-

我假设更改的表有4列,如下所示:

CREATE TABLE "TEST"."CHANGED" 
   (    "DEPTNO" NUMBER,"OLDVAL" NUMBER,"NEWVAL" NUMBER,"SEQ_NEXTVAL" NUMBER 
   ) ;

我们将序列值存储在seq_nextval列中.

在这种情况下,过程可能如下所示:

create or replace 
PROCEDURE pro_cedure( p_dept_id number  ) 
IS
      TYPE changed_table_type IS TABLE OF changed%ROWTYPE;
      changed_buff changed_table_type;
BEGIN
      SELECT deptno,extra,sequence_name.nextval 
        BULK COLLECT INTO changed_buff
        FROM emp
        WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id
        FOR UPDATE;
      UPDATE emp
        SET comm = extra
        WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id;
      FORALL i IN 1 .. changed_buff.count
        INSERT INTO changed VALUES changed_buff( i );
END;

—编辑—带光标的版本用于小数据集—–

是的,对于小型数据集批量收集不会显着提高速度,并且在这种情况下使用for..loop的普通光标就足够了.
下面是如何将游标与更新一起使用的示例,注意FOR UPDATE子句,当我们计划使用WHERE CURRENT OF子句更新从游标获取的记录时,它是必需的.
这次在INSERT语句中计算序列值.

create or replace 
PROCEDURE pro_cedure( p_dept_id number  ) 
IS
      CURSOR mycursor IS 
         SELECT deptno,extra
         FROM emp
         WHERE comm IS NULL AND extra IS NOT NULL 
               AND deptno = p_dept_id
         FOR UPDATE;    
BEGIN
      FOR emp_rec IN  mycursor
      LOOP
         UPDATE emp 
            SET comm = extra
            WHERE CURRENT OF mycursor;
         INSERT INTO changed( deptno,newval,seq_nextval)
                VALUES( emp_rec.deptno,emp_rec.comm,emp_rec.extra,sequence_name.nextval );
      END LOOP;
END;

(编辑:衡阳站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读