Oracle程序中的更新查询更新错误的值

时间:2011-11-09 10:22:12

标签: oracle sql-update oracle-xe

以下提到的程序旨在:

  1. 从cp_work_card中获取存在于cpTemplateWorkCard
  2. 中的jobid
  3. 从cp_work_card
  4. 中获取jobid的第一个bhours记录
  5. 将其更新为cpTemplateworkCard
  6. 但是,cpTemplateworkCard的所有行都使用最后一行中找到的bHours值进行更新。但是,执行时正确存储变量中的值

    DECLARE
         jobId       VARCHAR2(30);
         bHours      float;
         idx         NUMBER(4,0);
         CURSOR         c1 
         IS
            select distinct 
                   cp.job_id 
              from cp_work_card cp,
                   cptemplateworkcard temp 
             where cp.job_id = temp.JOBID;
    BEGIN
       idx:=1;
       DBMS_OUTPUT.PUT_LINE('id : jobId  :  bHours');
       OPEN c1;
       LOOP
          FETCH c1 INTO jobId;
          EXIT WHEN C1%NOTFOUND;
          select cpw.BUDGET_HOUR 
            into bHours 
            from cp_work_card cpw 
           where cpw.job_id=jobId 
             AND rownum<2;
          /*DBMS_OUTPUT.PUT_LINE('Budget Hours: '||bHours);
    
          UPDATE TO CPTEMPLATE*/
    
          UPDATE cptemplateworkcard tmpCard 
             SET tmpCard.BUDGET_HOUR=bHours 
           where tmpCard.JOBID=jobId;
    
          DBMS_OUTPUT.PUT_LINE(idx || ' : ' || jobId || ' : ' || bHours);
          idx:= idx+1;
    
       END LOOP;
    
       CLOSE c1;
    END;
    

2 个答案:

答案 0 :(得分:1)

使用单个SQL更新语句无法实现相同的效果吗?

UPDATE cptemplateworkcard tmpcard
   SET tmpcard.budget_hour = (SELECT budget_hour
                                FROM cp_work_card cp
                               WHERE cp.job_id = tmpcard.jobid
                                 AND rownum < 2)
 WHERE EXISTS
      (SELECT 1 
         FROM cp_work_card cp
        WHERE cp.job_id = tmpcard.jobid);

我没有测试过这个,但原理是一样的......

编辑:鉴于你的约束,如果你必须使用一个程序,那么你可以不:

DECLARE
   CURSOR c1
   IS
      SELECT DISTINCT
             cp.job_id,
             cp.budget_hour
        FROM cp_work_card cp
       INNER JOIN cptemplateworkcard temp
          ON (cp.job_id = temp.jobid)
       WHERE rownum < 2;
BEGIN
   DBMS_OUTPUT.put_line( 'job_id  :  budget_hour' );

   FOR c_rec IN c1
   LOOP
      UPDATE cptemplateworkcard tmpcard
         SET tmpcard.budget_hour = c_rec.budget_hour
       WHERE tmpcard.jobid = c_rec.job_id;

      DBMS_OUTPUT.put_line( c_rec.job_id || ' : ' || c_rec.budget_hour );
   END LOOP;
END;

编辑: 仅供参考,您当前的程序无效,因为您已将包含作业ID的变量命名为jobId,这也恰好是表cptemplateworkcard中列的名称。因此,当您执行更新时,它默认认为您的WHERE子句正在将表列与自身进行比较,从而使用bHours的值更新每一行。当程序结束时,显然是bHours的最后一个值,即从光标返回的最终值是什么,因此您看到表中的所有值都设置为此最终值。

如果您将jobId变量重命名为v_jobid,那么它应该可以解决问题。

希望它有所帮助...

如果唯一的限制是它必须在PL / SQL过程块中,那么这将是最有效的过程:

BEGIN
   UPDATE cptemplateworkcard tmpcard
      SET tmpcard.budget_hour = (SELECT budget_hour
                                   FROM cp_work_card cp
                                  WHERE cp.job_id = tmpcard.jobid
                                    AND rownum < 2)
    WHERE EXISTS
         (SELECT 1 
            FROM cp_work_card cp
           WHERE cp.job_id = tmpcard.jobid);

   DBMS_OUTPUT.put_line(SQL%rowcount||' record(s) updated');
END;

答案 1 :(得分:0)

如果您的陈述/条件都正确,那么执行以下语句而不是存储过程应该完全符合您的要求:

UPDATE cptemplateworkcard tc 
SET tc.BUDGET_HOUR=(SELECT cpw.BUDGET_HOUR FROM cp_work_card cpw where cpw.job_id=tc.JOBID AND rownum<2)
WHERE tc.JOBID IN (select cp.job_id from cp_work_card cp);