dynamic open for + ref cursor

KoTTT
Дата: 02.03.2007 13:57:50
В 8.1.7 это принципиально не работает?

DECLARE
   TYPE refcursor IS REF CURSOR;

   c     refcursor;
   l_c   DBMS_SQL.number_table;
BEGIN
   OPEN c FOR 'select rownum from all_objects where rownum < 1000';

   LOOP
      FETCH c
      BULK COLLECT INTO l_c LIMIT 100;

      FOR i IN 1 .. l_c.COUNT
      LOOP
         DBMS_OUTPUT.put_line (l_c (i));
      END LOOP;

      EXIT WHEN c%NOTFOUND;
   END LOOP;

   CLOSE c;
END;

В 9.2 - запросто...
KoTTT
Дата: 02.03.2007 14:23:51
Причем без bulk collect работает.
Jannny
Дата: 02.03.2007 14:32:05
Ну и чего Вам Оракл отвечает?
dmidek
Дата: 02.03.2007 14:33:08
Что говорит ?

P.S. Зачем OPEN FOR динамически пишете ?
KoTTT
Дата: 02.03.2007 14:46:33
Говорит

ORA-01001: invalid cursor

Зачем динамически.

Есть некая процедура, в которой есть огроменный инсерт по большому объему данных.
Если открывать статически курсор, оптимизатор рассчитывает план как с переменными привязки, что делает план напрочь неработоспособным на таких объемах. С литералами план нормальный. Вот и хотел динамически открывать, пусть 1 раз разберет нормально и 1 раз выполнит.

Пример выше привел чисто для описания проблемы.
dmidek
Дата: 02.03.2007 14:51:53
KoTTT
Говорит

ORA-01001: invalid cursor



Простите, а можно copy-paste сессии в sqlplus ?
KoTTT
Дата: 02.03.2007 15:00:05
SQL> select banner from v$version;

BANNER                                                                          
----------------------------------------------------------------                
Oracle8i Enterprise Edition Release 8.1.7.4.1 - Production                      
PL/SQL Release 8.1.7.4.0 - Production                                           
CORE	8.1.7.2.1	Production                                                       
TNS for 32-bit Windows: Version 8.1.7.4.0 - Production                          
NLSRTL Version 3.4.1.0.0 - Production                                           

SQL> DECLARE
  2     TYPE refcursor IS REF CURSOR;
  3  
  4     c     refcursor;
  5     l_c   DBMS_SQL.number_table;
  6  BEGIN
  7     OPEN c FOR 'select rownum from all_objects where rownum < 100';
  8  
  9     LOOP
 10        FETCH c
 11        BULK COLLECT INTO l_c LIMIT 10;
 12  
 13        FOR i IN 1 .. l_c.COUNT
 14        LOOP
 15           DBMS_OUTPUT.put_line (l_c (i));
 16        END LOOP;
 17  
 18        EXIT WHEN c%NOTFOUND;
 19     END LOOP;
 20  
 21     CLOSE c;
 22  END;
 23  /
DECLARE
*
ERROR at line 1:
ORA-01001: invalid cursor 
ORA-06512: at line 10 


SQL> spool off
dmidek
Дата: 02.03.2007 15:04:19
KoTTT
SQL> 


ОК. Спасибо.
Что произойдет
а. при декларировании OPEN FOR курсора статически ?
б. при явном статическом декларировании курсора
CURSOR cur_... IS ?
KoTTT
Дата: 02.03.2007 15:08:46
Если

OPEN c FOR select rownum from all_objects where rownum < 100;
или

CURSOR r IS SELECT ROWNUM FROM all_objects WHERE ROWNUM < 100;
...
OPEN c;

то все срабатывает.
KoTTT
Дата: 05.03.2007 08:14:13
Могу обрисовать проблему, может что и посоветуете.

Есть необходимость делать следующее

insert into table1
select pk, ... from ... table11
where table11.dat between d1 and d2
and ...

(Условию "table11.dat between d1 and d2" удовлетворяют около миллиона записей (~50% таблицы))

Затем, по всем только что вставленным pk (уникальным для table1)

loop
insert into table2
select ... from table22
where table22.col1 = pk
and ...;

insert into table3
select ... from table33
where table33.col1 = pk
and ...;

и т.д.
end loop;

Т.к. в insert into ... select ... нельзя использовать returning bulk collect into ..., хотелось сделать все это в виде

cursor c is
select pk, ... from ... table11
where table11.dat between d1 and d2
and ...

open c;
loop
fetch c bulk collect into ... limit N;
insert into table1 values (...) returning pk bulk collect into bc...

forall i in 1..bc.count
	insert into table2
	select ... from table22
	where table22.col1 = bc.pk
	and ...;

forall i in 1..bc.count
	insert into table3
	select ... from table33
	where table33.col1 = bc.pk
	and ...;

и т.д.

exit when c%notfound;
end loop;
Однако в любом варианте, план запроса в курсоре "c" будет неадекватным (доступ по индексам) из-за переменных привязки.
Поэтому решил открывать его динамически

open c for
'select pk, ... from ... table11
where table11.dat between ' || d1 || ' and ' || d2 ||
'and ...';

Но вот столкнулся с тем, что в 8.1.7 так нельзя в сочетании с "fetch c bulk collect into ...".

Подскажите, как можно проще и правильнее сделать? Чувствую, что можно, но найти способ сам пока не могу.