按照设置而不是迭代方法重写表更新

Dav*_*ner 1 oracle plsql

我在测试的Oracle数据库中有一个用户电子邮件地址列表,这些电子邮件地址当前都设置为相同的值。我想用唯一的条目替换这些条目,其中混入了许多无效地址和空值。我的表当前看起来像这样,总共约有25万行。(为节省空间,我排除了空条目和无效条目)

+-------------+--------------------+
| employee_id |       email        |
+-------------+--------------------+
|           1 | test@testemail.com |
|           2 | test@testemail.com |
|           3 | test@testemail.com |
|...          |...                 |
+-------------+--------------------+
Run Code Online (Sandbox Code Playgroud)

我希望它看起来像这样

+-------------+---------------------+
| employee_id |        email        |
+-------------+---------------------+
|           1 | test1@testemail.com |
|           2 | test2@testemail.com |
|           3 | test3@testemail.com |
|...          |...                  |
+-------------+---------------------+
Run Code Online (Sandbox Code Playgroud)

我编写了以下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;
/
Run Code Online (Sandbox Code Playgroud)

编辑-2016年9月26日-澄清表格的大小。

0xd*_*xdb 5

 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;
Run Code Online (Sandbox Code Playgroud)