小编典典

如何在oracle存储过程中创建和执行动态查询?

sql

我需要在存储过程中动态创建和执行查询。

我有两个表user和user_updates。

员工表有 emp_id, username, division, product, region, title etc.

Employee_updates具有类似以下的列 emp_id, effective_date, column_name, new_value etc.

基本上,这就是我想要做的。

  1. 获取所有在给定生效日期user_udates表中有更新的员工。

  2. 遍历每位员工。

  3. 获取给定生效日期的每位员工的所有更新。员工可能在employee_updates表中具有一个或多个更新。

  4. 根据这些更新创建动态的“ UPDATE”查询,例如

update employee set col1 = new_val_1, col2 = new_val_2 where emp_id = ?

这是我到目前为止所做的

    create or replace
PROCEDURE SP_RUN_EMPLOYEE_UPDATES 
(
  IN_DATE IN DATE
) 
  IS

    update_sql varchar2(225);

employee_id BI_EMPLOYEE_UPDATE.employee_id%TYPE;

    CURSOR  employees 
        IS   SELECT distinct(employee_id)
               FROM BI_EMPLOYEE_UPDATE 
             WHERE EFFECTIVE_DATE = to_date(IN_DATE,'dd-mm-yy') 
              AND EXECUTED = 'N' AND ACTIVITY_ID = '0'
              ;

    CURSOR e_updates 
    IS  SELECT * 
         FROM BI_EMPLOYEE_UPDATE 
        WHERE EFFECTIVE_DATE = to_date(IN_DATE,'dd-mm-yy') 
         AND EXECUTED = 'N' 
         AND ACTIVITY_ID = '0' 
         and employee_id = employee_id ;

     BEGIN

   OPEN employees;
   LOOP
    FETCH employees into employee_id;
        EXIT WHEN employees%NOTFOUND;

           FOR e_update in e_updates
         update_sql :=  'UPDATE BI_EMPLOYEE SET ';
              LOOP
                -- create dynam,ic update statment

                 UPDATE BI_EMPLOYEE_UPDATE
                 SET EXECUTED = 'Y'
                 WHERE EMPLOYEE_UPDATE_ID = e_update.EMPLOYEE_UPDATE_ID ;

                END LOOP;

            -- run dynamic sql

              END LOOP;
 CLOSE employees;
END;

请帮忙。


阅读 190

收藏
2021-04-22

共1个答案

小编典典

您在这里遇到一些问题,包括:

  • IN_DATE被声明为日期,因此您无需将其传递给TO_DATE()
  • 您只需要一个游标循环;如果employee_id出于某种原因要一起处理所有更新,则可以添加一个order by子句。
  • 您根本不需要动态SQL。您可以将游标中的值用作静态SQL更新的一部分。

因此,具有单个循环的简单版本可能类似于:

CREATE OR REPLACE PROCEDURE sp_run_employee_updates (p_date IN DATE) IS
    CURSOR c_updates IS
        SELECT *
        FROM bi_employee_update
        WHERE effective_date = p_date
        AND executed = 'N' 
        AND activity_id = '0'
        FOR UPDATE;     
BEGIN
    -- loop around all pending records
    FOR r_update IN c_updates LOOP
        -- apply this update to the bi_employee record
        UPDATE bi_employee
        SET col1 = r_update.col1, col2 = r_update.col2
        WHERE emp_id = r_update.employee_id;

        -- mark this update as executed
        UPDATE bi_employee_update
        SET executed = 'Y'
        WHERE CURRENT OF c_updates;
    END LOOP;
END sp_run_employee_updates;

这是使用for updateandwhere current of构造来锁定您正在使用的行并简化更新;请参阅此处的文档。

值得一提的是,如果其中一个effective_datep_date一个没有时间部分,它们将不匹配。这不太可能p_date,但更难猜测effective_date。如果确实如此,那么您要么需要trunc()它,要么用它between寻找一段时间。

2021-04-22