【问题标题】:How to write Execute immediate in cursor select Query如何在游标选择查询中编写立即执行
【发布时间】:2019-09-12 14:23:17
【问题描述】:

如何在游标选择查询中使用 EXECUTE IMMEDIATE。

CREATE OR REPLACE PROCEDURE biq_attendee_report (in_from_date IN DATE)
IS
   l_cur_query          VARCHAR2 (5000) := 'SELECT * from table X where c1='|| in_from_date;

   CURSOR cur_attendee_data
   IS
      EXECUTE IMMEDIATE  l_cur_query;

   TYPE rec_attendee_data IS TABLE OF cur_attendee_data%ROWTYPE
      INDEX BY PLS_INTEGER;

   l_cur_attendee_data  rec_attendee_data;
BEGIN
   OPEN cur_attendee_data;

   LOOP
      FETCH cur_attendee_data BULK COLLECT INTO l_cur_attendee_data;

      EXIT WHEN l_cur_attendee_data.COUNT = 0;
      DBMS_OUTPUT.put_line ('here in first insert');
      lrec := return_attendee_report ();
      out_attendee_tab :=
         return_attendee_arr_result (return_attendee_report ());
      out_attendee_tab.DELETE;

      FOR i IN 1 .. l_cur_attendee_data.COUNT
      LOOP
         BEGIN
            NULL;
         EXCEPTION
            WHEN OTHERS
            THEN
               DBMS_OUTPUT.put_line ('Error occurred : ' || SQLERRM);
         END;
      END LOOP;
   END LOOP;
EXCEPTION
   WHEN OTHERS
   THEN
      DBMS_OUTPUT.put_line ('HERE INSIIDE OTHERS' || SQLERRM);
END;

这里我尝试在开始块之外使用初始化游标,但它会引发异常,如何为游标编写动态查询,

cur_attendee_data is
EXECUTE IMMEDIATE  l_cur_query;

错误(113,8):PLS-00103:在预期以下情况之一时遇到符号“CUR_ATTENDEE_DATA”::=。 (@%;

【问题讨论】:

  • 你从哪里得到l_date?是in_from_date吗?
  • 你的代码中没有动态的东西(至少,看起来不是这样;l_cur_query 看起来不对;你发布了你真正拥有的东西吗?);为什么要使用execute immediate?此外,您“忘记”关闭光标。
  • @Littlefoot,如果你没有关闭光标,那将永远不会抛出错误。
  • @Ankit,打开的光标必须关闭 - 如果没有别的,因为有一个好的做法。除此之外,假设您打开它,从未关闭它,然后 - 在您的程序稍后 - 尝试再次打开相同的光标。那么,是的——它会抛出一个错误(ORA-06511: PL/SQL: cursor already open)。
  • 动态查询的原因是什么?

标签: sql oracle plsql


【解决方案1】:

如果你使用BULK COLLECT INTO ... 获取所有行,那么你只需要一个循环,第二个循环是没有用的。

基本的解决方案是这个:

CREATE OR REPLACE PROCEDURE biq_attendee_report (in_from_date IN DATE) IS

    l_cur_query          VARCHAR2 (5000) := 'SELECT * from {table X} where c1=:d';

   cur_attendee_data SYS_REFCURSOR;    
   TYPE rec_attendee_data IS TABLE OF {table X}%ROWTYPE;
   l_cur_attendee_data  rec_attendee_data;

BEGIN

    OPEN cur_attendee_data FOR l_cur_query USING in_from_date;
    FETCH cur_attendee_data BULK COLLECT INTO l_cur_attendee_data;

    FOR i IN 1 .. l_cur_attendee_data.COUNT LOOP
        -- do whatever you like to do with l_cur_attendee_data(i)
    END LOOP;
    CLOSE cur_attendee_data;

END;

但是,我认为没有任何理由制作动态 SQL。你可以简单地运行

CREATE OR REPLACE PROCEDURE biq_attendee_report (in_from_date IN DATE) IS    

   cur_attendee_data SYS_REFCURSOR;    
   TYPE rec_attendee_data IS TABLE OF {table X}%ROWTYPE;
   l_cur_attendee_data  rec_attendee_data;

BEGIN

    OPEN cur_attendee_data FOR SELECT * from {table X} where c1 = in_from_date;
    FETCH cur_attendee_data BULK COLLECT INTO l_cur_attendee_data;

    FOR i IN 1 .. l_cur_attendee_data.COUNT LOOP
        -- do whatever you like to do with l_cur_attendee_data(i)
    END LOOP;
    CLOSE cur_attendee_data;

END;

【讨论】:

  • 在我的实际查询中,我有不止一张表
  • 这些表的列是否都相同?
  • 那些表没有相同的列,这是我的实际查询。
【解决方案2】:

您可以改用以下代码 -

CREATE OR REPLACE PROCEDURE biq_attendee_report (in_from_date IN DATE)
IS
   l_cur_query          VARCHAR2 (100) := 'SELECT * from table X where c1=:in_from_date';

   TYPE t_cur IS REF CURSOR;
   cur_attendee_data t_cur

   TYPE rec_attendee_data IS TABLE OF cur_attendee_data%ROWTYPE
      INDEX BY PLS_INTEGER;

   l_cur_attendee_data  rec_attendee_data;
BEGIN
   OPEN cur_attendee_data FOR l_cur_query USING in_from_date;

   LOOP
      FETCH cur_attendee_data BULK COLLECT INTO l_cur_attendee_data;

      EXIT WHEN l_cur_attendee_data.COUNT = 0;
      DBMS_OUTPUT.put_line ('here in first insert');
      lrec := return_attendee_report ();
      out_attendee_tab :=
         return_attendee_arr_result (return_attendee_report ());
      out_attendee_tab.DELETE;

      FOR i IN 1 .. l_cur_attendee_data.COUNT
      LOOP
         BEGIN
            NULL;
         EXCEPTION
            WHEN OTHERS
            THEN
               DBMS_OUTPUT.put_line ('Error occurred : ' || SQLERRM);
         END;
      END LOOP;
   END LOOP;
EXCEPTION
   WHEN OTHERS
   THEN
      DBMS_OUTPUT.put_line ('HERE INSIIDE OTHERS' || SQLERRM);
END;

【讨论】:

    【解决方案3】:

    你需要使用''的打开光标如下:

    CREATE OR REPLACE PROCEDURE biq_attendee_report (in_from_date IN DATE)
    IS
       l_cur_query          VARCHAR2 (5000) := 'SELECT * from table X where c1='|| in_from_date;
       cur_attendee_data SYS_REFCURSOR; -- JUST DECLARED THE CURSOR
       --TYPE rec_attendee_data IS TABLE OF cur_attendee_data%ROWTYPE
       --   INDEX BY PLS_INTEGER; -- this declaration must be at schema level
       l_cur_attendee_data  rec_attendee_data;
    BEGIN
       OPEN cur_attendee_data for l_cur_query; -- OPEN THE CURSOR WITH DYNAMIC QUERY
       ..
       .. -- YOUR CODE AS IT IS
       ..
    

    干杯!!

    【讨论】:

    • 在哪里初始化类型 var "TYPE rec_attendee_data IS TABLE OF cur_attendee_data%rowtype INDEX BY PLS_INTEGER; l_cur_attendee_data rec_attendee_data;"
    • 将动态 SQL 与日期值连接起来真的很糟糕。更好地使用'SELECT * from table X where c1=:fromDate'; OPEN cur_attendee_data for l_cur_query using in_from_date;
    • 使用绑定变量和OPEN cursor_name FOR sql_string USING variable_name
    • 不起作用,你得到一个PLS-00320: the declaration of the type of this expression is incomplete or malformed
    • TYPE rec_attendee_data 是 cur_attendee_data%rowtype INDEX BY PLS_INTEGER 的表; l_cur_attendee_data rec_attendee_data;错误(109,18):PLS-00320:此表达式的类型声明不完整或格式错误,我们是否需要在类型声明中进行任何修改..?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-19
    • 1970-01-01
    • 2018-10-14
    • 1970-01-01
    • 1970-01-01
    • 2017-07-26
    • 1970-01-01
    相关资源
    最近更新 更多