通过 for 循环执行立即更新

Posted

技术标签:

【中文标题】通过 for 循环执行立即更新【英文标题】:Execute Immediate to UPDATE via for loop 【发布时间】:2013-03-22 02:41:40 【问题描述】:

我想做一些数据更新如下:

    CREATE OR REPLACE PROCEDURE PROC_MDM_RUN_DATA_MAPPING
     IS
        sqlString VARCHAR2(2000) := '';
        CURSOR csr_updates 
        IS
            SELECT  trim(table_name) AS table_name, 
                    trim(column_name) AS column_name, 
                    trim(old_value) AS old_value, 
                    trim(new_value) AS new_value 
            FROM C_MDM_MAPPING_TABLE 
            WHERE area = 'MDM' and rownum < 10
            AND run_update = 'Y' ;

    BEGIN
          FOR rec IN csr_updates 
          LOOP
             BEGIN
                sqlString := 'UPDATE ' || rec.table_name || 
                      ' SET ' || rec.column_name || ' = ''' || rec.new_value || '''
                      WHERE TRIM(' || rec.column_name || ') = ''' || rec.old_value || ''';'  ; 

                INSERT INTO C_MDM_ERROR_LOG  ( msg ) VALUES ( sqlString ); 

                dbms_output.put_line(sqlString) ; -- works, giving correct SQL
                execute immediate sqlString ;  -- fails

             END;
          END LOOP;
          COMMIT;

    END PROC_MDM_RUN_DATA_MAPPING;
    /

该过程为每个数据更新编译并生成正确的 SQL - 示例如下:

    UPDATE S_CFM_UNIVERSITY_ALL SET MASTER_UNI_NAME = 'Chung-Ang University'
                      WHERE TRIM(MASTER_UNI_NAME) = 'Chung Ang University';

但是执行立即语句给出了错误 “PLS-00103:在预期以下情况之一时遇到符号“文件结尾”:

; 符号“;”被替换为“文件结尾”以继续。”

我尝试排除尾随分号,但返回错误

  ORA-00933: SQL command not properly ended

任何帮助表示赞赏,谢谢。

【问题讨论】:

您在使用执行立即时不需要在 sqlstring 中使用分号,您确定您的游标查询正在返回所有列的值吗?可能有一行空值导致sql命令没有正确结束错误 是的,rs 在这点上是对的。删除动态SQL字符串中的;就可以了。 谢谢 rs - 所有列都返回值,但有些值包含单引号,我需要检查一下 【参考方案1】:

尝试在没有嵌入换行符的情况下生成 SQL,如下所示:

CREATE OR REPLACE PROCEDURE PROC_MDM_RUN_DATA_MAPPING IS
  sqlString VARCHAR2(2000) := '';

  CURSOR csr_updates IS
    SELECT  trim(table_name) AS table_name, 
            trim(column_name) AS column_name, 
            trim(old_value) AS old_value, 
            trim(new_value) AS new_value 
      FROM C_MDM_MAPPING_TABLE 
      WHERE area = 'MDM' AND
            rownum < 10 AND
            run_update = 'Y';
  BEGIN
    FOR rec IN csr_updates LOOP
      sqlString := 'UPDATE ' || rec.table_name || 
                   ' SET ' || rec.column_name || ' = ''' || rec.new_value ||
                   ''' WHERE TRIM(' || rec.column_name || ') = ''' ||
                   rec.old_value || '''';

      INSERT INTO C_MDM_ERROR_LOG  ( msg ) VALUES ( sqlString ); 

      dbms_output.put_line(sqlString) ; -- works, giving correct SQL
      execute immediate sqlString ;
    END LOOP;

    COMMIT;
  END PROC_MDM_RUN_DATA_MAPPING;

我删除了生成的 SQL 中的分号,因为我认为它是不需要的,并删除了循环内的 BEGIN...END 对,这也是不需要的。

我希望这会有所帮助。分享和享受。

【讨论】:

【参考方案2】:

感谢所有帮助 - 上面的答案是正确的,因为不需要尾随分号,但作为后续 - 有第二个问题是数据中的单引号。

如下更改光标修复了该问题

    SELECT  trim(table_name) AS table_name, 
            trim(column_name) AS column_name, 
            REPLACE(trim(old_value),'''','''''') AS old_value, 
            REPLACE(trim(new_value),'''','''''') AS new_value 
    FROM C_MDM_MAPPING_TABLE 

已知表名和列名没问题(它们来自系统),但它又回到“从不信任输入”。

谢谢

【讨论】:

以上是关于通过 for 循环执行立即更新的主要内容,如果未能解决你的问题,请参考以下文章

c#通过for循环多次向数据库中插入数据。

在 redux store 更新后立即执行自定义回调

三. var let const的理解 以及 立即执行函数中的使用 以及 for循环中的例子

组件卸载时停止执行我的 React for 循环

在循环中立即执行获取表数据

浅析Vue.nextTick()原理