我是PL / SQL的新手。我需要更新表employee_details中的电话号码,其中旧电话号码和新电话号码存储在另一个表phone_no中(列old_phone_no
和new_phone_no
)
我想取phone_no
(old_phone_no
和new_phone_no
)中的第一行,并在employee_details上执行update语句,即(update employee_details set phone_no=new_phone_no where phone_no=old_phone_no
)定期提交;
在我们遍历phone_no表中的所有行之前,应该继续相同的过程。
寻找Stack Overflow上所有专家的答案。
Create statements.
--Table which needs to be updated
CREATE TABLE EMPLOYEE_DETAILS
(
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
PhoneNumber varchar(255)
);
-- Temp Table which contains old and new phone numbers
CREATE TABLE PHONE_NO
(
PersonID int,
OldPhone varchar(255),
NewPhone varchar(255)
);
我在考虑定期提交,因为我在EMPLOYEE_DETAILS
中有大约1000万行,EMPOYEE_DETAILS
中有很多行用于单个电话号码,即来自表OldPhone
的{{1}}
我不想打扰生产性能。如果还有其他方法可以做,我没事。
以下方法是否有效。
DECLARE CURSOR all_phones IS 选择OldPhone,NewPhone 来自PHONE_NO 订购OldPhone;
PHONE_NO
BEGIN 打开all_phones; FETCH all_phones BULK收集进入phone_olds,phone_news; 关闭all_phones;
TYPE phone_old IS TABLE OF PHONE_NO.OldPhone%TYPE;
TYPE phone_new IS TABLE OF PHONE_NO.NewPhone%TYPE;
phone_olds phone_old;
phone_news phone_new;
inx1 PLS_INTEGER;
END;
此致 周杰伦。
答案 0 :(得分:0)
这样的事情可能有用(未经过测试),但我不确定您是否可以更新已用于JOIN
的列,因为它会使连接无效:
DECLARE
CURSOR c IS SELECT pn.newphone
FROM employee_details ed
JOIN phone_no pn ON pn.oldphone = ed.phonenumber
FOR UPDATE OF ed.phonenumber;
row_count INTEGER := 0;
commit_frequency CONSTANT INTEGER := 10000;
BEGIN
FOR rec IN c LOOP
UPDATE employee_details
SET phonenumber = rec.newphone
WHERE CURRENT OF c;
row_count := row_count + 1;
IF MOD(row_count, commit_frequency) = 0 THEN
COMMIT;
END IF;
END LOOP;
END;
你最好在employee_details.phonenumber
上有一个索引!
同样,您可以执行以下操作,如果没有级联效果,则应该可以使用:
DECLARE
commit_frequency CONSTANT INTEGER := 10000;
BEGIN
FOR rec IN ( SELECT oldphone, newphone
FROM phone_no
)
LOOP
UPDATE employee_details
SET phonenumber = rec.newphone
WHERE phonenumber = rec.oldphone;
row_count := row_count + 1;
IF MOD(row_count, commit_frequency) = 0 THEN
COMMIT;
END IF;
END LOOP;
END;
级联效应存在以下问题:
EMPLOYEE_DETAILS
name | surname | phonenumber
-----+---------+-------------
John | Doe | +1 234 5678
Mike | Lee | +1 098 7654
PHONE_NO
oldphone | newphone
------------+------------
+1 098 7654 | +1 357 9135
+1 234 5678 | +1 098 7654
在这里,John Doe的电话号码可以更新一次或两次。
答案 1 :(得分:0)
你知道触发器吗?在这种情况下,这将是最好的操作方式。触发是在特定条件之后执行的自动动作。在你的情况下,你可以做
CREATE OR REPLACE TRIGGER my_trigger
AFTER UPDATE ON your_table
FOR EACH ROW
DECLARE
BEGIN
INSERT INTO phone_no
(old_phone_no, new_phone_no)
VALUES
(OLD.phoneNumber, NEW.phoneNumber);
END;
/
对于每行更新,此代码只会在更新后在表格中插入旧电话号码和新电话号码。 希望它有所帮助! - Nic
答案 2 :(得分:0)
如果您的数据库基础架构不能有效处理大量负载,那么我能想到的最好的方法是使用LIMIT条件的BULK COLLECT方法。希望下面片段有帮助。我现在没有工作区,所以请原谅任何语法错误。
DECLARE
TYPE lv_nphn IS TABLE OF phone_number .newphone%TYPE;
TYPE lv_ophn IS TABLE OF phone_number .oldphone%TYPE;
TYPE lv_empno IS TABLE OF employee_details.empno %TYPE;
lv_nph_tab lv_nphn;
lv_oph_tab lv_ophn;
lv_empno_tab lv_empno;
CURSOR c
IS SELECT pn.newphone,
pn.oldphone,
ed.empno
FROM employee_details ed
JOIN phone_no pn
ON pn.oldphone = ed.phonenumber;
BEGIN
OPEN C;
LOOP
FETCH C BULK COLLECT INTO lv_oph_tab,lv_nph_tab,lv_empno_tab LIMIT 10000;
EXIT WHEN lv_nph_tab.COUNT = 0;
FORALL I IN lv_nph_tab.FIRST..lv_nph_tab.LAST
UPDATE employee_details
SET phonenumber = lv_nph_tab(i)
WHERE empno = lv_empno_tab(i);
COMMIT;
END LOOP;
END;
答案 3 :(得分:0)
我只想更新它:
alter table phone_no add constraint phone_pk primary key(oldphone);
update ( select e.phonenumber, p.newphone
from employee_details e
join phone_no p on p.oldphone = e.phonenumber )
set phonenumber = newphone;
然后担心你是否有足够的撤销资源等,如果它实际上是一个问题。
(需要约束,因为必须将oldphone声明为唯一才能避免
ORA-01779: cannot modify a column which maps to a non key-preserved table
。您可以使用普通唯一索引或主键或唯一键约束来执行此操作。)