【问题标题】:pl/sql - Using a dynamic query inside a stored procedurepl/sql - 在存储过程中使用动态查询
【发布时间】:2011-02-15 18:20:05
【问题描述】:

我正在使用存储过程通过游标将数据插入到临时表中。 此过程将动态查询存储在变量中以挂载插入/更新命令。

这里是代码(不是完整的查询,我剪掉了一些部分以便于阅读):

 FOR VC2 IN (SELECT C.OBJETIVO,
                C.AUDITORIA ,
                C.NOME, 
                C.PRODUTO
           FROM CALCULO C)
  LOOP

  SELECT  ' V_UPD NUMBER := 0;

              SELECT (SELECT ID_TIPO_TERR  
              FROM ZREPORTYTD_TMP 
             WHERE AUDITORIA = ''' || VC2.AUDITORIA || '''
                AND TERRITORIO = ''' || VC2.NOME  || '''
                AND PRODUTO = ''' || VC2.PRODUTO || ''') 
               INTO V_UPD FROM DUAL;

                  UPDATE ZReportYTD_TMP
                     SET  TARGET = ' || VC2.OBJETIVO  || '
                   WHERE AUDITORIA = ''' || VC2.AUDITORIA || '''
                     AND TERRITORIO = ''' || VC2.NOME  || '''
                     AND PRODUTO = ''' || VC2.PRODUTO || ''';'

               INTO V_SQL  FROM DUAL;

               EXECUTE IMMEDIATE (V_SQL);

  END LOOP

在动态查询中,这部分"SET TARGET = ' || VC2.OBJETIVO || '" 的值VC2.OBJETIVONumber 类型,它被替换为“62481,76”。换句话说,这个逗号使命令出错并且不起作用。

有没有一种简单的方法可以将“,”替换为“。”?

非常感谢! (:

【问题讨论】:

  • OBJETIVO 的数据类型是什么?
  • 那么我不知道为什么它会返回数字作为格式化值。
  • 你不知道为什么它会像现在这样返回或者为什么我想做我想做的事?
  • 出了什么问题?是不是报错了?或者你没有得到想要的结果?
  • @Cyber​​nate - 它以格式化值的形式返回数字,因为它必须转换为字符串才能附加到 SQL。真的不是要走的路。

标签: oracle plsql


【解决方案1】:

不要通过附加字符串来构建查询。首先是 SQL 注入,您会让自己面临许多错误和漏洞。需要使用动态查询并不能证明不使用绑定变量是合理的。如果您确实需要使用动态查询(从您的示例中不清楚为什么静态更新不起作用?!),请改为:

FOR vc2 IN (...) LOOP
   v_sql := 
       'BEGIN
            V_UPD NUMBER := 0;

            SELECT (SELECT ID_TIPO_TERR  
              FROM ZREPORTYTD_TMP 
             WHERE AUDITORIA = :p1
               AND TERRITORIO = :p2
               AND PRODUTO = :p3) 
              INTO V_UPD FROM DUAL;

            UPDATE ZReportYTD_TMP
               SET TARGET = :p4
             WHERE AUDITORIA = :p5
               AND TERRITORIO = :p6
               AND PRODUTO = :p7;
        END';
   EXECUTE IMMEDIATE v_sql USING VC2.AUDITORIA, VC2.NOME, VC2.PRODUTO, 
                                 VC2.OBJETIVO, VC2.AUDITORIA, VC2.NOME, 
                                 VC2.PRODUTO;
END LOOP;

Oracle 将正确绑定到适当的类型。

【讨论】:

  • 谢谢文森特,我会尝试使用这种方法。
  • 像 Auditoria 和 Territorio 这样的 varchar2 类型的字段不需要放在' '里面吗?
  • @dev_gabriel:不,这就是让 Oracle 进行绑定的美妙之处 :)
【解决方案2】:

我认为根本不需要使用动态 SQL。

为什么不这样:

FOR VC2 IN (SELECT C.OBJETIVO,
                C.AUDITORIA ,
                C.NOME, 
                C.PRODUTO
           FROM CALCULO C) LOOP

    v_upd := 0;

    SELECT
        ID_TIPO_TERR
    into
        v_UPD
    FROM
        ZREPORTYTD_TMP 
    WHERE
        AUDITORIA = VC2.AUDITORIA
    AND TERRITORIO = VC2.NOME
    AND PRODUTO = VC2.PRODUTO;

    -- is v_upd used anywhere?

    UPDATE
        ZReportYTD_TMP
    SET
        TARGET = VC2.OBJETIVO
    WHERE
        AUDITORIA = VC2.AUDITORIA
    AND TERRITORIO = VC2.NOME
    AND PRODUTO = VC2.PRODUTO;

END LOOP;

【讨论】:

  • 谢谢尼克,但确实需要动态使用它。我只是没有正确解释它并且没有粘贴完整的代码。感谢您的帮助,但文森特的方法已经解决了我的问题(:
【解决方案3】:

我使用的是 Oracle 11g,前几天我遇到了以下问题 在 oracle 过程中执行动态查询。我确实搜索了很多。 终于有办法了。

-- In blow procedure we pass multiple argument at run time 
-- We need reference cursor for dynamic query execution
create or replace  PROCEDURE FETCH_REPORT1_NEW(IPID IN number ,CAID IN number,
ZOID IN  number,CLID IN number,SDATE VARCHAR2 , EDATE
VARCHAR2,OUT_VALUE OUT VARCHAR2)

IS

  l_sql varchar(200);   TYPE cursor_ref IS REF CURSOR;   c1
cursor_ref;

  UZID transaction_data.zone_id%TYPE;   OUTAGE_MINS
transaction_data.durationmin%TYPE;

BEGIN

    l_sql := 'select  Avg (durationmin) , zone_id ,
     from transaction_data where  alarm_id in (1,21,26,20) and  zone_id not in(5)';

      IF IPID>0 THEN  

       l_sql := l_sql||' and  IP_ID = '||IPID;

      END IF;         


        l_sql := l_sql||' group by (zone_id)';
       open c1 for l_sql;

          loop
              fetch c1 into OUTAGE_MINS,UZID;

                       dbms_output.put_line(OUTAGE_MINS||UZID);

              exit when c1%notfound;

          end loop;
     close c1; 
    END;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-12
    • 1970-01-01
    • 1970-01-01
    • 2015-01-28
    • 1970-01-01
    • 2019-03-17
    • 1970-01-01
    相关资源
    最近更新 更多