1

部門 40 と 70 の従業員の給与を更新する必要があります。部門 40 のすべての従業員は 10% 増加し、部門 70 の従業員は 15% 増加します。

部門 70 の従業員が 1 人いて、給与が 10000 であるため、彼の給与は 15% 増加します。彼の給料は 11500 になると思っていたのですが、13225 になってしまいました。理由がわかりません。部門 40 の従業員の昇給は正しく、部門 70 の従業員のみが間違っています。

ここにpl/sqlブロックがあります..

SET serveroutput ON
DECLARE

  CURSOR cur_emp
  IS
    SELECT * FROM employees WHERE department_id = 40 OR department_id = 70;
  rec_emp cur_emp%rowtype;
BEGIN
  OPEN cur_emp;
  LOOP
    FETCH cur_emp INTO rec_emp;
    IF rec_emp.department_id = 40 THEN
      UPDATE employees
      SET salary                = salary + (salary * 0.1)
      WHERE employee_id         = rec_emp.employee_id;
    elsif rec_emp.department_id = 70 THEN
      UPDATE employees
      SET salary        = salary + (salary * 0.15)
      WHERE employee_id = rec_emp.employee_id;
    END IF;
    EXIT
  WHEN cur_emp%notfound;
  END LOOP;
  CLOSE cur_emp;
END;
/

誰かがこの問題を解決するのを手伝ってくれますか? ありがとう

4

1 に答える 1

4

ストアドプロシージャは必要ありません。

update employees
   set salary = case 
                  when department_id = 40 then salary * 1.10
                  when department_id = 70 then salary * 1.15
                  else salary -- not strictly necessary. just to make sure.
                end
where department_id in (40,70);

を使用して低速な方法(PL / SQLのループ)を実行することを主張する場合はUPDATE ... WHERE CURRENT OF、「無関係な」更新よりもおそらく高速です。

コードの本当の問題は、ループを「遅すぎる」ままにしておくことです。フェッチ後にカーソルが何も返さない場合でも、更新を実行します。IF句と更新のEXIT WHEN ... に置く必要があります。

DECLARE

  CURSOR cur_emp
  IS
    SELECT * FROM employees WHERE department_id = 40 OR department_id = 70;
  rec_emp cur_emp%rowtype;
BEGIN
  OPEN cur_emp;
  LOOP
    FETCH cur_emp INTO rec_emp;

    EXIT WHEN cur_emp%notfound; -- **** leave the loop right here, BEFORE doing the update *****

    IF rec_emp.department_id = 40 THEN
      UPDATE employees
      SET salary                = salary + (salary * 0.1)
      WHERE employee_id         = rec_emp.employee_id;
    elsif rec_emp.department_id = 70 THEN
      UPDATE employees
      SET salary        = salary + (salary * 0.15)
      WHERE employee_id = rec_emp.employee_id;
    END IF;

  END LOOP;
  CLOSE cur_emp;
END;
/

より効率的な方法は、更新可能なカーソルを使用することです。

DECLARE

  CURSOR cur_emp
  IS
    SELECT department_id, salary 
    FROM employees 
    WHERE department_id in (40,70)
    FOR UPDATE OF salary;

  rec_emp cur_emp%rowtype;
  new_sal number(12,2);
BEGIN
  OPEN cur_emp;
  LOOP
    FETCH cur_emp INTO rec_emp;

    EXIT WHEN cur_emp%NOTFOUND;

    IF rec_emp.department_id = 40 THEN
      new_sal := rec_emp.salary * 1.10;
    elsif rec_emp.department_id = 70 THEN
      new_sal := rec_emp.salary * 1.15;
    END IF;

    UPDATE employees
       SET salary  = new_sal
    WHERE CURRENT OF cur_emp;

  END LOOP;
  CLOSE cur_emp;
END;
/

を使用すると、WHERE CURRENT OF実際にはエラーがより明確になります。これは、更新後にafterinvalid rowidを配置すると、ループが失敗するためです。exit

于 2012-11-15T07:41:09.227 に答える