2011-06-06 100 views
3

我有两种类型一种优雅的方式通过表通过每个条目

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; 
/

改造的索引,在PL/SQL简单的表,其他则环是否有用10g的优雅方式替换类似

的变换部分
v_table = CAST(v_hash as my_table_type) 
+1

它看起来像你不关心'v_hash'中的实际键*自己*,只是他们的顺序。如果是这样的话,为什么要使用INDEX BY表呢? – Dan 2011-06-06 17:04:46

+1

如果'MY_HASH_TYPE'是一个'MY_RECORD_TYPE'表,就像'MY_TABLE_TYPE'一样,为什么不直接声明V_HASH类型为'MY_TABLE_TYPE'?然后,你可以取消V_TABLE并只返回V_HASH。除非您的示例代码中缺少您的业务逻辑的某些细微之处。 – APC 2011-06-06 19:01:02

+0

@APC:我在' - 这里使用了一些业务逻辑中的哈希部分:) – schurik 2011-06-07 08:46:02

回答

4

您可以使用SELECT my_record_type(column_value) BULK COLLECT INTO v_table from table(v_hash)。但为了使用它,您必须在函数之外创建my_hash_type(作为包装规格中的类型,以便SQL引擎可以看到它),否则您将收到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 

有一些例子看看herehere和诸如此类的东西

定时差(based on this methodology#分别是在百分之一秒为单位)

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。Array类型 - 希望我错了!)

+0

+1很好的解决方案,但是不会因交换机造成性能影响** plsql-> sql-> plsql ** ? – schurik 2011-06-07 09:05:25

+0

@schurik,我在sql-pl/sql开关和循环之间添加了一些时间差异。您会注意到循环时间减少了50%。 – Harrison 2011-06-07 12:30:51

+0

感谢您对我的问题的详细调查,但是您在**之外定义的**类型意味着什么? – schurik 2011-06-07 13:04:42