Oracle函数中对变量赋值不起作用,用的是oracle11g

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle函数中对变量赋值不起作用,用的是oracle11g相关的知识,希望对你有一定的参考价值。

create or replace
FUNCTION toTestReturn
(
costcenterId varchar2
)
RETURN int
IS
rootId varchar2 (32);
sumnum int;
BEGIN
rootId := nvl(costcenterId, '0');
--select count(pid) into rootId from costcenterinfo where ID=rootId;
select count(pid) into sumnum from costcenterinfo where id=costcenterId;

RETURN sumnum;
END toTestReturn;

当我用select count(pid) into sumnum from costcenterinfo where id=costcenterId;时,sql调用函数是能返回sumnum=1的,但是当我使用注释的select count(pid) into rootId from costcenterinfo where ID=rootId;,sql调用函数返回的是null

不知道什么原因
上面的函数有点错误,应该是这样的:
create or replace
FUNCTION toTestReturn
(
costcenterId varchar2
)
RETURN varchar2
is
rootId varchar2 (32);
temp varchar2 (32);
BEGIN
rootId := nvl(costcenterId, '0');
select pid into temp from costcenterinfo where ID=rootId;
RETURN temp;

END toTestReturn;

现在调用函数时传的值肯定是不为空且pid也肯定有值,但是返回temp为null

参考技术A --select count(pid) into rootId from costcenterinfo where ID=rootId;
select count(pid) into sumnum from costcenterinfo where id=costcenterId;

RETURN sumnum;

因为你返回的是sumnum,使用注释的你赋值给了rootId 所有返回NULL。

在 PL/SQL 函数的 EXECUTE IMMEDIATE 中使用 UDT 变量

【中文标题】在 PL/SQL 函数的 EXECUTE IMMEDIATE 中使用 UDT 变量【英文标题】:Using UDT variable within an EXECUTE IMMEDIATE in a PL/SQL function 【发布时间】:2017-03-20 21:16:51 【问题描述】:

我正在使用 Oracle 11g 在 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 * from TABLE(knn_join('london','cophirfv','fv','fv','manhattan',5)); 

我正在尝试使用运行语句 'SELECT join_t(ROWIDTOCHAR(r.rowid), center_objects(idx).id) BULK COLLECT INTO join_table FROM london r WHERE manhattan_knn(r.fv, center_objects(idx).fv)

有人可以帮我看看吗?

提前致谢!

【问题讨论】:

center_objects 是动态 SQL 上下文中不存在的本地 PL/SQL 变量。您可以用绑定变量替换第一个引用,但不能替换第二个。你为什么使用两个查询;为什么不使用单个查询进行连接,然后将其批量收集到retval 在这种情况下我不能使用连接,因为我使用的函数 (manhattan_dis) 只接受一个元素作为第二个参数,所以这就是我使用这个 'center_object' 的原因变量和两个语句。实际上,这就是我必须构建此功能的原因。 【参考方案1】:

您不能在动态 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 || ')<='...

尽管 - 至少在您展示的示例中 - 唯一可用的对象属性名称是 fv,无论传入函数的表列名称如何 - 因此可以硬编码;因此可以使用绑定变量:

... ',  :fv)<='...
EXECUTE IMMEDIATE ... USING center_objects(idx).id, center_objects(idx).fv ...

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

据我所知,您仍然可以在动态 SQL 语句中进行连接,并消除循环以及对中间 center_objectsjoin_table 集合的需要:

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

...所以我想您可以验证该硬编码版本是否首先为您提供了您期望的结果。 (当然,在问题中添加样本数据和预期结果会有所帮助)。

连接条件可能很昂贵,具体取决于函数正在执行的操作、每个表中的行数(因为每个表中的每一行都必须与另一个表中的每一行进行比较)、您是否真的有其他过滤器等。虽然循环版本会更糟。如果没有更多信息,无论如何也没什么可做的。

顺便说一句,对象属性使用varchar2 而不是char 会更正常;这也是the rowidtochar() function返回的数据类型。

【讨论】:

谢谢!有用!!好吧,正如我在另一条评论中告诉你的那样,我无法通过函数 manhattan 进行任何连接,但是使用绑定变量的函数运行良好。 @Siqueira - 使用一些虚拟数据,它们对我做的事情完全相同。您的真实数据可能存在问题,但我无法想象它会是什么。我不确定您为什么不能使用联接(或者为什么您认为不能)。一次只将一组值(一对 tab_inn 和 tab_out 行中的一个)传递给函数。 是的,我知道......这就是函数的用途......将对象一一传递给函数。而且真的不行……manhattan函数不支持第二个参数是这样的…… @Siqueira - 每个表中单行的 blob 值 (fv) 都被传递给 manhattan_knn() - 不是对象 - 所以不太确定你的意思或有什么区别是。但是很明显有些东西你没有展示出来,所以我假设你知道你在说什么,当你尝试时,简单的版本实际上不起作用。祝你好运...

以上是关于Oracle函数中对变量赋值不起作用,用的是oracle11g的主要内容,如果未能解决你的问题,请参考以下文章

oracle存储过程中,我声明了数字型变量a,并赋值。随后我想修改a的值为a=a+1.该怎么写???

AVG 中的 TO_NUMBER 函数不起作用

java 函数参数赋值不起作用

求教ORACLE的问题,我用的是ORACLE 9I,出现一个ORA-00600:内部错误代码,参数:[qernsRowP],[1],[]....

python中对变量的作用域LEGB闭包装饰器基本理解

坑向: 关于在Navicat中对Oracle数据库表空间的数据文件进行重命名和修改路径时报错ORA-01511,ORA-01121,ORA-01110的解决办法