IN子句的函数或过程

时间:2009-02-18 16:31:58

标签: oracle ora-01722

我想编写一个可以在另一个过程的IN子句中使用的函数或过程。该函数或过程将返回ID号。

主要程序会说类似

SELECT *
FROM EMPLOYEES
WHERE OFFICE_ID IN (GET_OFFICE_IDS);  -- GET_OFFICE_IDS requires no parameters

GET_OFFICE_IDS返回一个VARCHAR2,ID以逗号分隔。当我运行主程序时,我得到一个“ORA-01722:无效数字”错误,这是有道理的,但我不知道我需要从这里去哪里。

我是否需要GET_OFFICE_IDS来创建主程序使用的临时表?如果是这样,是否会有性能损失?

5 个答案:

答案 0 :(得分:6)

以下是嵌套表解决方案的工作示例,使用EMP表:

create type t_ids is table of integer
/

create or replace function get_office_ids return t_ids
is
   l_ids t_ids := t_ids();
   l_idx integer := 0;
begin
   for r in (select empno from emp where deptno=10)
   loop
      l_ids.extend;
      l_idx := l_idx+1;
      l_ids(l_idx) := r.empno;
   end loop;
   return l_ids;
end;
/

select ename from emp where empno in (select * from table(get_office_ids));


ENAME
----------
CLARK
KING
TEST
MILLER
BINNSY
FARMER

答案 1 :(得分:3)

简单的蛮力方法:

WHERE ','||GET_OFFICE_IDS||',' LIKE '%,'||OFFICE_ID||',%'

最好更改GET_OFFICE_IDS以返回嵌套表并使用类似的内容:

OFFICE_ID IN (SELECT * FROM TABLE(GET_OFFICE_IDS))

答案 2 :(得分:2)

我没有使用oracle SQL,但是你不能简单地在IN子句中添加另一个select语句来返回ID吗?

SELECT * FROM EMPLOYEES WHERE OFFICE_ID IN(SELECT ID FROM tbl_X WHERE x = y);

......或者你希望做一些更复杂的事情?

答案 3 :(得分:1)

您可以使用ref_cursor(ref cursor c:='select'|| ....)

但是流水线功能非常有效。 像这样使用它:

create or replace type type_varchar2 as table of varchar2(100);

create or replace function GET_OFFICE_IDS return TYPE_varchar2 PIPELINED
is
  retval VARCHAR2(100);
begin
  -- put some sql here which results in statements as below
 retval := '135';
 PIPE ROW (retval);
 retval := '110';
 PIPE ROW (retval);
end GET_OFFICE_IDS;


select *
from entries
where id in (SELECT COLUMN_VALUE FROM TABLE(GET_OFFICE_IDS));

通常,流水线功能表现非常好。 但是,具有大量条目的子查询并不总是非常好。

答案 4 :(得分:1)

编辑:我打破了SO的基本规则,我没有回答OP。由于已经有一个公认的答案,我觉得谨慎警告。

通常,混合SQL和PL / SQL是一个非常糟糕的主意。代码有2个独立的引擎。有一个SQL引擎和一个PL / SQL引擎。强迫数千个交换机来回绝对会破坏性能。

我理解为什么程序员想要这样做。我知道了。这一切都是封闭的,温暖的和模糊的,但它会严重损害你。就像大自然一样,它会以它的视线和声音诱惑你,然后它会打破你的脚踝。

即使是像这样愚蠢的东西。

create or replace function my_Date (p_Date in date)
return varchar
as
begin

    return to_char(p_Date, 'yyyy/mm/dd');

end;

杀死你的执行时间。

转动启用自动跟踪

然后运行这些。

select to_char(created, 'yyyy/mm/dd'), to_char(last_ddl_time, 'yyyy/mm/dd')  from all_objects


select my_date(created), my_Date(last_DDL_TIME) From all_objects

第二个需要两倍的时间才能运行。我得到的答案是1秒钟内查询1秒,2秒钟内2秒钟。

这是一个非常简单的案例 ...我正在做的就是投射值。想象一下,如果你必须像你想要的那样加入它。那真是最糟糕的情况。

现在想想当你在函数中隐藏东西时优化器完全无法做到的事情。

当您进行IN时,有时候连接速度要快得多。如果某些条件为真,优化器将为您执行此操作。它会将IN转换为JOIN。但是因为你伪装了函数内部的选择,它不再能确定条件是否成熟。您已经强制优化器以次优方式执行某些操作。

优化器依赖的一个关键统计信息是rowcount。是一行还是十亿。它从表和索引的统计数据中知道。您的功能没有统计数据。

你可以把它们放在那里,有可能暗示基数,我不是说你不能,但为什么呢?你为什么想要?看起来你正在使用这个功能,因为你是一个勤奋的程序员,一直被告知将冗余代码分解为函数。

你头脑中的那些规则几乎都不适用于SQL。优化器不是编译器。它无法内联您的功能。只有您可以帮助优化人员获得最佳计划。