[英]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.