当通过内联select语句调用函数时,当函数返回自定义类型时,Oracle似乎执行的函数等于参数+1的数量.当选择包括在CTAS或插入/选择中时,似乎会发生这种情况.
谁看过这个吗?这是Oracle的错误吗?我希望在表中每行调用一次该函数.
--Inline function gets called for the number of arguments +1
--drop table t
create table t(
  id number,
  l_blob blob
);
insert into t values(1, utl_raw.cast_to_raw('SampleString'));
COMMIT;
create table tmp_ts (c1 timestamp); 
create or replace type test_type as object(
              c1         varchar2(32)
              ,c2  varchar2(32)
        );
/
create or replace FUNCTION test_function (p_blob blob, p_date date)
RETURN test_type
IS
BEGIN
--This could also be a DBMS_OUTPUT.PUT_LINE statement
insert into tmp_ts VALUES (systimestamp);
return test_type(null,null);
END test_function;
/
--0
select count(*) from tmp_ts;
--Call function on 1 row table - function should just insert 1 row into tmp_ts
create table tst_table as
select test_function(l_blob, '25-JAN-09') as c1
from t;
--it actually inserts 3
select count(*) from tmp_ts;
增加类型的参数调用的示例增加了函数执行的时间
--Inline function gets called for the number of arguments +1
--drop table t
create table t2(
  id number,
  l_blob blob
);
insert into t2 values(1, utl_raw.cast_to_raw('SampleString'));
COMMIT;
create table tmp_ts2 (c1 timestamp); 
create or replace type test_type2 as object(
              c1         varchar2(32)
              ,c2  varchar2(32)
              ,c3  varchar2(32)
              ,c4  varchar2(32)
              ,c5  varchar2(32)
              ,c6  varchar2(32)
        );
/
create or replace FUNCTION test_function2 (p_blob blob, p_date date)
RETURN test_type2
IS
BEGIN
insert into tmp_ts2 VALUES (systimestamp);
return test_type2(null,null,null,null,null,null);
END test_function2;
/
--0
select count(*) from tmp_ts2;
--Call function on 1 row table - function should just insert 1 row into tmp_ts
create table tst_table2 as
select test_function2(l_blob, '25-JAN-09') as c1
from t;
--it actually inserts 7
select count(*) from tmp_ts2;
非常感谢任何帮助/反馈.
首先:这是一个错误,您甚至可以在 SELECT 语句中调用的函数内执行 DML。这应该引发异常。
否则,Oracle 绝对不保证 SQL-Select 中函数的执行频率,可能每行执行一次、每行十次或整个查询仅执行一次(带缓存) - 因此无论调用频率如何,这都符合规格。
在这种特殊情况下,它将为返回类型的每个属性调用该函数,因为 Oracle 不会将对象类型作为一个内存结构插入,而是像具有多列的表一样使用该函数,并单独读取每一列,如下所示:
INSERT VALUES ( myFunc(x).attribute1, myFunc(x).attribute2 );
The important part: Never make any assumptions about how often a FUNCTION is called when you use it in an SQL Statement!!! At any time the function could be called again by the optimizer, maybe for sampling or caching...
Preferred solution: Pipelined Functions - a pipelined Function can be called like a Table and will only be called once. You can pass in a cursor which the function uses for input processing and do the whole data-transformation and logging and everything in the function.