Элегантный способ преобразовать индекс по таблице в простую таблицу в PL / SQL, а затем циклически проходить каждую запись - PullRequest
3 голосов
/ 06 июня 2011

У меня есть два типа

CREATE OR REPLACE TYPE my_record_type IS OBJECT
  (
    name        varchar2(30)
  )
  ;

CREATE OR REPLACE TYPE my_table_type AS TABLE OF my_record_type

и функция

create or replace my_function return my_table_type
is
  type my_hash_type is table of my_record_type index by pls_integer;
  v_hash my_hash_type;
  v_table my_table_type;
  i NUMBER;
begin
 -- some business logic here

 -- transformation part

 v_table := my_table_type();
 i := v_hash.first;

 while i is not null loop

  v_table.extend(1);
  v_table(v_table.last) := v_hash(i);
  i := v_hash.next(i); 

 end loop;

 --  end transformation part

 return v_table;
end;
/

Есть ли в 10g элегантный способ заменить деталь преобразования чем-то вроде

v_table = CAST( v_hash as  my_table_type )

1 Ответ

4 голосов
/ 06 июня 2011

Вы можете использовать SELECT my_record_type(column_value) BULK COLLECT INTO v_table from table(v_hash).Но для того, чтобы использовать это, вам нужно будет создать my_hash_type вне функции (либо в качестве самостоятельного типа ИЛИ в спецификации пакета, чтобы он был виден SQL Engine), в противном случае вы получитеPLS-00642: local collection types not allowed in SQL statements.

CREATE OR REPLACE TYPE my_hash_type is table OF VARCHAR2(10);
/
set serveroutput on
declare 
 --type my_hash_type is table OF VARCHAR2(10);
  v_hash my_hash_type := my_hash_type();
  v_table my_table_type;
  i NUMBER;
begin
null ;
  for n in 60..75 loop
    V_hash.extend(1);  
    V_hash(v_hash.count) := chr(n) ;
  end loop ;

  select my_record_type(column_value)
  bulk collect into  v_table
  from table(v_hash) ;

  for n in 1..v_table.count loop
    dbms_output.put_line( n || ':>' || v_table(n).name);
  end loop ;

  --PLS-00642: local collection types not allowed in SQL statements

end ;

1:><
2:>=
3:>>
4:>?
5:>@
6:>A
7:>B
8:>C
9:>D
10:>E
11:>F
12:>G
13:>H
14:>I
15:>J
16:>K

посмотрите здесь и здесь еще несколько примеров и еще много чего

различия во времени (на основе )по этой методологии # в сотнях секунд)

pl/sql context switch (as described above)
44
42
43
42

loop fill (with type defined outside of block) --A distinct CREATE TYPE on Oracle level

18
18
18
18

loop fill (with type defined within block) --Type created within the Anon. block
23
22
24
22

(вышеуказанные испытания времени были вариациями на основе этого кода:

set serveroutput on
declare 
 --type my_hash_type  is table of my_record_type -index by pls_integer;
  v_hash my_hash_type := my_hash_type();
  v_table my_table_type;
  i NUMBER;
  time_before BINARY_INTEGER; 
  time_after BINARY_INTEGER;
begin

time_before := DBMS_UTILITY.GET_TIME; 

  for n in 0..15000 loop
    V_hash.extend(1);  
    V_hash(v_hash.count) := my_record_type(n) ;
  end loop ;


  select my_record_type(column_value)
  bulk collect into  v_table
  from table(v_hash) ;


  /*
  v_table := my_table_type();
  for n in 1..V_hash.count loop
    v_table.extend(1);
    v_table(v_table.count) := v_hash(n) ;
    --dbms_output.put_line( n || ':>' || v_table(n).name);
  end loop ;*/
  --for n in 1..v_table.count loop
  --  dbms_output.put_line( n || ':>' || v_table(n).name);
  --end loop ;
time_after := DBMS_UTILITY.GET_TIME; 

DBMS_OUTPUT.PUT_LINE (time_after - time_before);
  --PLS-00642: local collection types not allowed in SQL statements

end ;
/

Таким образом, заполнение циклаНа 50% быстрее, но разница во времени все еще ничтожна (вот баланс между преждевременной оптимизацией и избеганием чего-либо, потому что это может быть слишком долго, я бы рекомендовал провести временные испытания ваших реальных данных, чтобы найти решение, которое лучше всего подходит).

Единственное другое «элегантное» решение, которое я могу придумать, это TREAT , но вы заметите, что для этого требуется решение подтипа / супертипа, которое должно быть на объектном типе (я не смог получитьэто работать на Varray / Assoc.Тип массива - надеюсь, я ошибаюсь!)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...