我在测试Oracle数据库中有一个用户电子邮件地址列表,它们当前都设置为相同的值。我想用唯一的条目替换它们,其中包含许多无效的地址和空值。我的表目前看起来像这样,总共大约250k行。(我已经排除了空和无效的条目来保存一些空间)
+-------------+--------------------+
| employee_id | email |
+-------------+--------------------+
| 1 | test@testemail.com |
| 2 | test@testemail.com |
| 3 | test@testemail.com |
|... |... |
+-------------+--------------------+
我希望它看起来像这样
+-------------+---------------------+
| employee_id | email |
+-------------+---------------------+
| 1 | test1@testemail.com |
| 2 | test2@testemail.com |
| 3 | test3@testemail.com |
|... |... |
+-------------+---------------------+
我已经编写了以下PL / SQL来进行更改,它可以正常工作,但它似乎非常低效。我可以使用其他方法来利用集合处理吗?
感谢您提供任何帮助。
DECLARE
i number(20);
l_employee_id hr.employees.employee_id%TYPE;
output_query varchar2(1000);
CURSOR c_cursor IS
SELECT employee_id
FROM hr.employees;
PROCEDURE update_sql(id_num IN hr.employees.employee_id%TYPE,
email IN VARCHAR2) IS
BEGIN
output_query := 'UPDATE hr.employees
SET email = '''|| email ||'''
WHERE employee_id = '|| id_num;
dbms_output.put_line(output_query); --for debug
EXECUTE IMMEDIATE output_query;
END;
BEGIN
OPEN c_cursor;
i := 1;
<<outer_loop>>
LOOP
For j IN 1..5 LOOP
FETCH c_cursor INTO l_employee_id;
EXIT outer_loop WHEN c_cursor%NOTFOUND;
IF j <= 3 THEN
update_sql(l_employee_id, ('test' || i || '@testemail.com'));
ELSIF j = 4 THEN
update_sql(l_employee_id, ('test' || i || 'testemail.com'));
ELSIF j = 5 THEN
update_sql(l_employee_id, ' ');
END IF;
i := i + 1;
END LOOP;
END LOOP outer_loop;
CLOSE c_cursor;
END;
/
编辑 - 2016年9月26日 - 澄清表的大小。
答案 0 :(得分:4)
create table emp (emp_id number, email varchar2(32));
insert into emp select level as emp_id, 'test@testemail.com' as email
from dual connect by level<=2500000;
update emp set email = regexp_replace(email, '(\w+)(@\w+\.\w+)', '\1' || emp_id || '\2');
--250,000 rows updated ~16 sec.
EMP_ID, EMAIL
1 test1@testemail.com
2 test2@testemail.com
3 test3@testemail.com
...
drop table emp;
答案 1 :(得分:2)
首先,即使你要迭代编码,请不要在没有必要的情况下使用动态SQL。只有在编译时不知道要查询的表或列时才有必要。
那就是说,听起来你只是想要
UPDATE employees
SET email = (case when employee_id <= 3
then 'test' || employee_id || '@testemail.com'
when employee_id = 4
then 'test' || employee_id || 'testemail.com'
when employee_id = 5
then ' '
else null
end)
答案 2 :(得分:0)
Oracle安装程序:
create table employees (
id NUMBER,
email VARCHAR2(100)
);
INSERT INTO employees
SELECT 1, 'test@testemail.com' FROM DUAL UNION ALL
SELECT 2, 'test@testemail.com' FROM DUAL UNION ALL
SELECT 3, 'test@testemail.com' FROM DUAL UNION ALL
SELECT 4, 'test@testemail.com' FROM DUAL UNION ALL
SELECT 5, 'test@testemail.com' FROM DUAL UNION ALL
SELECT 6, 'test@testemail.com' FROM DUAL;
<强>查询强>:
update employees
set email = CASE MOD( ROWNUM, 5 )
WHEN 4 THEN 'test' || ROWNUM || 'testemail.com'
WHEN 0 THEN ''
ELSE 'test' || ROWNUM || '@testemail.com'
END;
<强>输出强>:
SELECT * FROM employees;
ID EMAIL
---------- ------------------------
1 test1@testemail.com
2 test2@testemail.com
3 test3@testemail.com
4 test4testemail.com
5
6 test6@testemail.com