在PL/SQL函数的执行立即数中使用UDT变量

在PL/SQL函数的执行立即数中使用UDT变量,sql,oracle,plsql,execute-immediate,Sql,Oracle,Plsql,Execute Immediate,我正在使用Oracle11g在PL/SQL上构建一个函数 我试图在EXECUTE IMMEDIATE语句中使用表变量,但它不起作用,如您所见: ERROR at line 1: ORA-00904: "CENTER_OBJECTS": invalid identifier ORA-06512: at "HIGIIA.KNN_JOIN", line 18 我使用的代码是 首先,类型定义 CREATE TYPE join_t IS OBJECT ( inn

我正在使用Oracle11g在PL/SQL上构建一个函数

我试图在EXECUTE IMMEDIATE语句中使用表变量,但它不起作用,如您所见:

ERROR at line 1:
ORA-00904: "CENTER_OBJECTS": invalid identifier
ORA-06512: at "HIGIIA.KNN_JOIN", line 18
我使用的代码是

首先,类型定义

CREATE TYPE join_t IS OBJECT (
   inn                          char(40),
   out                        char(40)
);
/


CREATE TYPE join_jt IS TABLE OF join_t;
/

CREATE TYPE blob_t IS OBJECT (
   id           CHAR(40),
   fv           BLOB
);
/

CREATE TYPE blob_tt IS TABLE OF blob_t;
/
功能是:

create or replace FUNCTION knn_join (tab_inn IN varchar2, tab_out IN varchar2, blob_col1 IN varchar2, blob_col2 IN varchar2, dist_alg in VARCHAR2, kv in NUMBER ) RETURN join_jt
IS
var_fv BLOB;
var_id CHAR(40);
center_objects blob_tt := blob_tt();
retval join_jt := join_jt ();
join_table join_jt := join_jt();
sql_stmt1 varchar2(400);
sql_stmt2 varchar2(400);
BEGIN
    sql_stmt1 := 'SELECT blob_t(ROWIDTOCHAR(rowid),' || blob_col1 || ') FROM ' || tab_out;
    sql_stmt2 := 'SELECT join_t(ROWIDTOCHAR(r.rowid), center_objects(idx).id) FROM ' || tab_inn || ' r  WHERE ' || dist_alg || '_knn(r.' || blob_col2 || ',  center_objects(idx).' ||   blob_col1 || ')<=' || kv;
    dbms_output.put_line(sql_stmt2);    
    EXECUTE IMMEDIATE sql_stmt1 BULK COLLECT INTO center_objects;
    for idx in center_objects.first()..center_objects.last()
                loop
                --SELECT join_t(ROWIDTOCHAR(r.rowid), center_objects(idx).id) BULK COLLECT INTO join_table FROM londonfv r WHERE manhattan_knn(r.fv, center_objects(idx).fv) <=5;
                EXECUTE IMMEDIATE sql_stmt2 BULK COLLECT INTO join_table;   
            for idx2 in join_table.first()..join_table.last()
                   loop
                            retval.extend();
                        retval(retval.count()) := join_table(idx2);
                       end loop;
            end loop;
RETURN retval;
END;
/

我试图使用语句“SELECT join_t(ROWIDTOCHAR(r.rowid),center_objects(idx).id)BULK COLLECT从伦敦r运行到join_表中,在那里manhattan_knn(r.fv,center_objects(idx).fv)您不能在动态SQL语句中引用本地PL/SQL变量,因为它超出了动态调用所使用的SQL上下文的范围。您可以替换您的第一个电话:

SELECT join_t(ROWIDTOCHAR(r.rowid), center_objects(idx).id) FROM ' ...
使用绑定变量:

SELECT join_t(ROWIDTOCHAR(r.rowid), :id FROM ' ...
EXECUTE IMMEDIATE ... USING center_objects(idx).id ...
但如果对象属性也是可变的,则无法执行以下操作:

... ',  center_objects(idx).' ||   blob_col1 || ')<='...
kv
值也应该是一个绑定变量,因此您将得到:

create or replace FUNCTION knn_join (tab_inn IN varchar2, tab_out IN varchar2,
  blob_col1 IN varchar2, blob_col2 IN varchar2, dist_alg in VARCHAR2, kv in NUMBER )
RETURN join_jt
IS
  center_objects blob_tt := blob_tt();
  retval join_jt := join_jt ();
  join_table join_jt := join_jt();
  sql_stmt1 varchar2(400);
  sql_stmt2 varchar2(400);
BEGIN
  sql_stmt1 := 'SELECT blob_t(ROWIDTOCHAR(rowid),' || blob_col1 || ') FROM ' || tab_out;
  sql_stmt2 := 'SELECT join_t(ROWIDTOCHAR(r.rowid), :id) FROM ' || tab_inn || ' r  WHERE '
    || dist_alg || '_knn(r.' || blob_col2 || ',  :fv)<= :kv';
  dbms_output.put_line(sql_stmt1);    
  dbms_output.put_line(sql_stmt2);    
  EXECUTE IMMEDIATE sql_stmt1 BULK COLLECT INTO center_objects;
  for idx in center_objects.first()..center_objects.last()
  loop
    EXECUTE IMMEDIATE sql_stmt2 BULK COLLECT INTO join_table
    USING center_objects(idx).id, center_objects(idx).fv, kv;   
    for idx2 in join_table.first()..join_table.last()
    loop
      retval.extend();
      retval(retval.count()) := join_table(idx2);
    end loop;
  end loop;
  RETURN retval;
END;
/
如图所示,当您调用它时:

select * from TABLE(knn_join('london','cophirfv','fv','fv','manhattan',5)); 
这相当于硬编码:

SELECT join_t(ROWIDTOCHAR(tinn.rowid), ROWIDTOCHAR(tout.rowid))
FROM london tinn
JOIN cophirfv tout
ON manhattan_knn(tinn.fv, tout.fv) <= 5
选择加入(ROWIDTOCHAR(tinn.rowid)、ROWIDTOCHAR(tout.rowid))
伦敦锡
加入cophirfv兜售

在manhattan_knn(tinn.fv,tout.fv)
center_对象
是一个在动态SQL上下文中不存在的本地PL/SQL变量。可以用绑定变量替换第一个引用,但不能替换第二个引用。为什么要使用两个查询;为什么不使用一个执行联接的查询,并将其批量收集到
retval
?在这种情况下,我不能使用联接,因为我使用的函数(manhattan_dis)只接受一个元素作为第二个参数,这就是我使用这个“center_object”变量和两个语句的原因。事实上,这就是我必须构建这个函数的原因。谢谢!它起作用了!!正如我在另一条评论中告诉你的那样,我无法通过函数manhattan进行任何连接,但是使用绑定变量的函数工作得很好。@Siqueira-对于一些伪数据,它们对我的作用完全相同。你的真实数据可能有问题,但我无法想象会是什么。我不确定为什么不能使用联接(或者为什么认为不能)。一次只向函数传递一组值(一对tab_inn和tab_out行各一个)。是的,我知道。。。这就是这个功能的目的。。。。将对象逐个传递给函数。而且它真的不起作用。。。manhattan函数不支持第二个参数是这样的…@Siqueira-来自每个表中单个行的blob值(
fv
)都被传递到
manhattan\u knn()
-而不是对象-因此不确定您的意思或区别是什么。但很明显,有些东西你还没有展示出来,所以我假设你知道你在说什么,而简单的版本在你尝试它时实际上不起作用。祝你好运
create or replace FUNCTION knn_join (tab_inn IN varchar2, tab_out IN varchar2,
  blob_col1 IN varchar2, blob_col2 IN varchar2, dist_alg in VARCHAR2, kv in NUMBER )
RETURN join_jt
IS
  retval join_jt;
  sql_stmt varchar2(400);
BEGIN
  sql_stmt := 'SELECT join_t(ROWIDTOCHAR(tinn.rowid), ROWIDTOCHAR(tout.rowid))'
    || ' FROM ' || tab_inn || ' tinn JOIN ' || tab_out || ' tout'
    || ' ON ' || dist_alg || '_knn(tinn.fv, tout.fv) <= :kv';

  dbms_output.put_line(sql_stmt);
  EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO retval USING kv;
  RETURN retval;
END;
/
select * from TABLE(knn_join('london','cophirfv','fv','fv','manhattan',5)); 
SELECT join_t(ROWIDTOCHAR(tinn.rowid), ROWIDTOCHAR(tout.rowid))
FROM london tinn
JOIN cophirfv tout
ON manhattan_knn(tinn.fv, tout.fv) <= 5