[英]Update table inside a loop in a procedure pl/sql
所以我想為一個部門聘請一位新經理。 此過程有 2 個參數,我要更改的部門名稱和經理的新 ID(取自員工的 ID)。 因此,要更改它,我需要更新所有擁有舊經理 ID 的員工,並將他們的經理 ID 更改為新經理 ID。 到目前為止,這是我的代碼,問題是它更新了所有員工的經理,所以整個數據庫都更新了。 我必須使用過程,而不是函數。 任何的想法? 謝謝。
CREATE OR REPLACE PROCEDURE update_manager(v_deptname IN departments.department_name%TYPE,v_empid IN employees.employee_id%TYPE) IS
v_deptid departments.department_id%type;
BEGIN
SELECT department_id INTO v_deptid FROM departments WHERE department_name=v_deptname;
FOR i IN (SELECT * FROM employees)
LOOP
IF i.department_id=v_deptid THEN
UPDATE employees
SET manager_id=v_empid
WHERE i.department_id=v_deptid;
END IF;
END LOOP;
END;
/
BEGIN
update_manager('Marketing',100);
END;
/
我沒有你的桌子,但我有斯科特的所以 - 這是一個例子。
部門10的部門和員工:
SQL> select * From dept order by deptno;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> select deptno, empno, ename, mgr
2 from emp
3 where deptno = 10;
DEPTNO EMPNO ENAME MGR
---------- ---------- ---------- ----------
10 7782 CLARK 7839
10 7839 KING
10 7934 MILLER 7782
看起來像你的程序(當你正在學習 PL/SQL 時),使用一個變量來獲取部門編號,以及一個循環:
SQL> create or replace procedure update_manager
2 (v_deptname in dept.dname%type,
3 v_empno in emp.empno%type
4 )
5 is
6 v_deptno dept.deptno%type;
7 begin
8 select d.deptno
9 into v_deptno
10 from dept d
11 where d.dname = v_deptname; --> this is what you are missing
12
13 for cur_r in (select e.empno
14 from emp e
15 where e.deptno = v_deptno
16 )
17 loop
18 update emp a set
19 a.mgr = v_empno
20 where a.empno = cur_r.empno;
21 end loop;
22 end;
23 /
Procedure created.
測試:讓我們修改部門 10 中所有員工的經理:
SQL> exec update_manager ('ACCOUNTING', 7839);
PL/SQL procedure successfully completed.
SQL> select deptno, empno, ename, mgr
2 from emp
3 where deptno = 10;
DEPTNO EMPNO ENAME MGR
---------- ---------- ---------- ----------
10 7782 CLARK 7839
10 7839 KING 7839
10 7934 MILLER 7839
SQL>
似乎工作。 但是,這是低效的; 逐行(在循環中)這樣做通常是緩慢的。 而是處理整組數據。 像這樣的東西:
SQL> rollback;
Rollback complete.
SQL> create or replace procedure update_manager
2 (v_deptname in dept.dname%type,
3 v_empno in emp.empno%type
4 )
5 is
6 begin
7 update emp e set
8 e.mgr = v_empno
9 where e.deptno = (select d.deptno
10 from dept d
11 where d.dname = v_deptname
12 );
13 end;
14 /
Procedure created.
SQL> exec update_manager ('ACCOUNTING', 7782);
PL/SQL procedure successfully completed.
SQL> select deptno, empno, ename, mgr
2 from emp
3 where deptno = 10;
DEPTNO EMPNO ENAME MGR
---------- ---------- ---------- ----------
10 7782 CLARK 7782
10 7839 KING 7782
10 7934 MILLER 7782
SQL>
如果您必須創建一個 PL/SQL 過程,那么您可以這樣做
CREATE OR REPLACE PROCEDURE update_manager(v_deptname IN departments.department_name%TYPE,v_empid IN employees.employee_id%TYPE) IS
v_deptid departments.department_id%type;
BEGIN
SELECT department_id INTO v_deptid FROM departments WHERE department_name=v_deptname;
UPDATE employees
SET manager_id=v_empid
WHERE department_id=v_deptid;
END;
/
您的代碼導致“它更新了所有員工的經理”的問題是您的更新語句:
UPDATE employees
SET manager_id=v_empid
WHERE i.department_id=v_deptid;
您在這里的過濾器正在比較i.department_id
,這是來自您的FOR i IN (SELECT * FROM employees)
的變量,而不是來自更新語句的變量。 您已經確認i.department_id=v_deptid
因為您正在循環中調用它並使用if
語句檢查它。
獲取員工中的所有行,循環結果,檢查每一行是否與條件匹配,然后觸發更新語句(即使您的更新語句針對正確的行進行過濾)根本沒有效率。
為什么不簡單地選擇經理 ID 和所有相關員工的更新?
DECLARE @department_id uniqueidentifier
SELECT @department_id = departement_id
FROM departments
WHERE department_name = @v_deptname
UPDATE employees
SET manager_id = @v_empid
WHERE department_id = @department_id
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.