我想编写一个可以在另一个过程的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来创建主程序使用的临时表?如果是这样,是否会有性能损失?
答案 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。优化器不是编译器。它无法内联您的功能。只有您可以帮助优化人员获得最佳计划。