2011-06-06 96 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