Oracle IN子句的功能或过程

Oracle IN子句的功能或过程,oracle,ora-01722,Oracle,Ora 01722,我想写一个可以在另一个过程的in子句中使用的函数或过程。函数或过程将返回ID号 主要程序会说 SELECT * FROM EMPLOYEES WHERE OFFICE_ID IN (GET_OFFICE_IDS); -- GET_OFFICE_IDS requires no parameters GET_OFFICE_ID返回一个VARCHAR2,ID用逗号分隔。当我运行主程序时,我得到一个ORA-01722:无效数字错误,这是有意义的,但我不知道我需要从这里走到哪里 我是否需要获取办公室I

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

主要程序会说

SELECT *
FROM EMPLOYEES
WHERE OFFICE_ID IN (GET_OFFICE_IDS);  -- GET_OFFICE_IDS requires no parameters
GET_OFFICE_ID返回一个VARCHAR2,ID用逗号分隔。当我运行主程序时,我得到一个ORA-01722:无效数字错误,这是有意义的,但我不知道我需要从这里走到哪里


我是否需要获取办公室ID来创建主过程使用的临时表?如果是的话,会不会有绩效处罚

我不熟悉oracle SQL,但是您不能简单地在in子句中放入另一个select语句来返回ID吗

从员工中选择*,其中办公室ID位于从tbl\U X中选择ID,其中X=y


…还是你希望做一些更复杂的事情?

简单的暴力方法:

WHERE ','||GET_OFFICE_IDS||',' LIKE '%,'||OFFICE_ID||',%'
最好将GET_OFFICE_id更改为返回嵌套表,并使用以下内容:

OFFICE_ID IN (SELECT * FROM TABLE(GET_OFFICE_IDS))

下面是使用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

您可能可以使用ref|u光标ref cursor c:=“选择”| |

但是流水线函数工作得非常好。 像这样使用它:

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));
通常,流水线函数执行得非常好。 但是,一个包含大量条目的子查询的性能并不总是很好。

编辑:我违反了SO的基本规则,所以我没有回答OP。因为已经有一个可接受的答案,我觉得谨慎地警告一下

通常,混合使用SQL和PL/SQL是一个非常糟糕的主意。代码有两个单独的引擎。有一个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时,有时候做一个join要快得多。如果某些条件为真,优化器将为您执行此操作。它将IN转换为联接。但是,由于在函数中隐藏了select,因此它无法再确定条件是否成熟。您已强制优化器以次优方式执行某些操作

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

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


在您的头脑中,这些规则几乎都不适用于SQL。优化器不是编译器。它无法内联您的函数。只有您可以帮助优化器获得最佳计划。

这更复杂,因为实际的SELECT语句有大约五个级别的子查询,将在我的程序中使用,这就是为什么我想将其放在函数或过程中。您是否可以保存查询/视图以检索所需的记录,并执行类似的操作-从qryrequiredofficeid中插入select id?这样,您就可以重用程序中其他位置的查询。HTHPerhaps嵌套表是一种方法。我得仔细阅读一下。我不经常使用它们。使用这种SQL,您将无法在嵌套查询中执行select*,因为它将返回多个列。嵌套表是否意味着磁盘访问,即性能损失,还是只是Oracle为该集合类型提出的一个术语?嵌套表只是一种集合类型的名称。在这种情况下,它将只是在内存中。您也可以将它们存储在表中,在这种情况下,它们将存储在磁盘上。当我从不同的用户进行并发访问时,我是否需要担心数据交叉,或者这是自动处理的?不,嵌套的表数据对每个用户的会话都是私有的。