An elegant way to transform an index by table into simple table in PL/SQL, other then loop through every entry
I have two types
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
and a function
create or replace my_function return my_table_type
is
type my_hash_type is table of my_record_type index by pls_integer;开发者_如何学JAVA
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;
/
Is there an elegant way in 10g to replace the transformation part with something like
v_table = CAST( v_hash as my_table_type )
You may use the SELECT my_record_type(column_value) BULK COLLECT INTO v_table from table(v_hash)
. But in order to use this, you will have to create my_hash_type outside of a function (either as a stand along type OR in a Package Specification so it will be visible to the SQL Engine) otherwise you will receive a 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
have a look here and here for some more examples and whatnot
timing differences (based on this methodology #s are in hundreths of a second)
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
(the above time trials were variations based on this code:
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 ;
/
Thus the loop fill is 50% faster, but the time difference is still minuscule (here is the balance between premature optimization and avoiding something because it may be too long, I would recommend doing time trials on your real data to find the solution that best fits).
The only other 'elegant' solution I can think of is TREAT, but you'll notice it requires a subtype/supertype solution that must be on an object type (I couldn't get it to work on an Varray/Assoc. Array type -- hopefully I'm wrong!)
精彩评论