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

时间:2012-09-11 12:52:19

标签: sql oracle stored-procedures

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

我有两个表users和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 = ?

  5. 这是我到目前为止所做的事情

        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;
    

    提供帮助。

1 个答案:

答案 0 :(得分:4)

这里有一些问题,包括:

  • 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 updatewhere current of构造来锁定您正在使用的行并简化更新;请参阅文档here

值得注意的是,如果effective_datep_date都有时间成分,则它们将无法匹配。 p_date不太可能,但effective_date更难猜测。如果是,则您需要trunc(),或使用between查找一系列时间。