在 PL/SQL 中将表索引转换为简单表的优雅方法,然后循环遍历每个条目

发布于 2024-11-13 08:45:11 字数 811 浏览 3 评论 0原文

我有两种类型

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 )

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

老旧海报 2024-11-20 08:45:11

您可以使用SELECT my_record_type(column_value) BULK COLLECT INTO v_table from table(v_hash)。但为了使用它,您必须在函数外部创建 my_hash_type (作为包规范中的独立类型 OR ,以便 SQL 引擎可见),否则您将收到a PLS-00642:SQL 语句中不允许使用本地集合类型

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

看看这里此处了解更多示例以及

时间差异等(基于此方法 #s 为百分之一秒)

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 上工作) 。数组类型——希望我错了!)

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!)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文