IN 子句的函数或过程
我想编写一个可以在另一个过程的 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 来创建主过程使用的临时表? 如果是这样,是否会有性能损失?
I want to write a funcion or procedure that can be used in the IN clause of another procedure. The function or procedure would return ID numbers.
The main procedure would say something like
SELECT *
FROM EMPLOYEES
WHERE OFFICE_ID IN (GET_OFFICE_IDS); -- GET_OFFICE_IDS requires no parameters
GET_OFFICE_IDS returns a VARCHAR2 with the ID separated by commas. When I run the main procedure, I get a "ORA-01722: invalid number" error which makes sense but I don't know where I need to go from here.
Do I need GET_OFFICE_IDS to create a temp table that the main procedure uses? If so, will there be a performance penalty?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
以下是使用 EMP 表的嵌套表解决方案的工作示例:
Here is a working example of the nested table solution, using the EMP table:
简单的强力方法:
最好更改 GET_OFFICE_IDS 以返回嵌套表并使用类似以下内容的内容:
The simple brute force approach:
It would better to change GET_OFFICE_IDS to return a nested table and use something like:
我不熟悉 oracle SQL,但是您不能简单地在 IN 子句中放置另一个 select 语句来返回 ID 吗?
SELECT * FROM EMPLOYEES WHERE OFFICE_ID IN (SELECT ID FROM tbl_X WHERE x=y);
...或者您希望做一些更复杂的事情?
I'm not up on oracle SQL, but are you not able to simply put another select statement in the IN Clause to return the IDs?
SELECT * FROM EMPLOYEES WHERE OFFICE_ID IN (SELECT ID FROM tbl_X WHERE x=y);
...or were you hoping to do something a bit more complicated?
您可能可以使用 ref_cursor 来完成此操作(refcursor c := 'select '||.... ),
但是管道函数效果很好。
像这样使用它:
通常管道函数执行得很好。
然而,具有大量条目的子查询的性能并不总是很好。
You can probably do this with a ref_cursor (ref cursor c := 'select '||.... )
But a pipelined function works very well.
use it like this:
Normally a pipelined function performs very well.
However a subquery with A LOT of entries performs not always very good.
编辑:我违反了SO的基本规则,我没有回答OP。 由于已经有一个可接受的答案,因此我认为警告是明智的。
通常,混合 SQL 和 PL/SQL 是一个非常糟糕的主意。 有 2 个独立的代码引擎。 有一个 SQL 引擎和一个 PL/SQL 引擎。 强制来回进行数千次切换绝对会降低性能。
我明白为什么程序员要这样做。 我得到它。 这一切都是封装的、温暖的、模糊的,但它会让你精疲力竭。 就像大自然一样,它会用它的景象和声音引诱你,然后它会折断你的脚踝。
即使是这样愚蠢的事情。
将杀死你的执行时间。
打开打开自动跟踪,
然后运行它们。
第二个需要两倍的时间来运行。 我在 1 秒内得到查询 1 的答案,在 2 秒内得到查询 2 的答案。
这是一个极其简单的案例...我所做的只是转换值。 想象一下,如果您必须按照自己的意愿加入其中。 这确实是最坏的情况。
现在想想当您将某些内容隐藏在函数中时优化器完全无法执行哪些操作。
当您执行 IN 时,有时执行 join 的速度要快得多。 如果某些条件成立,优化器将为您执行此操作。 它将把 IN 转换为 JOIN。 但由于您在函数内隐藏了选择,因此它无法再确定条件是否成熟。 您强制优化器做了一些次优的事情。
优化器依赖的一项关键统计数据是行计数。 是一行还是10亿。 它从表和索引的统计数据中得知。 您的函数没有统计数据。
你可以把它们放在那里,可以暗示基数,我并不是说你不能,但为什么呢? 你为什么想要这么做? 看来您正在使用该函数,因为您是一位勤奋的程序员,一生都被告知要将冗余代码分解到函数中。
你脑子里的那些规则几乎没有一个适用于 SQL。 优化器不是编译器。 它不能内联你的函数。 只有您才能帮助您的优化器获得最佳计划。
EDIT: I broke the cardinal rule of SO, I didn't answer the OP. Since there already is an accepted answer, I felt it prudent to warn.
As a rule, it's a very bad idea to mix SQL and PL/SQL. There are 2 separate engines for code. There's a SQL engine and a PL/SQL engine. Forcing thousands of switches back and forth will absolutely kill performance.
I understand why programmers want to do this. I get it. It's all encapsulately and warmy and fuzzy but it will sap you badly. Like nature it will seduce you with its sights and its sounds and then it will break your ankle.
Even something as stupid as this.
Will Kill your execution time.
Turn turn on autotrace
then run these.
The second one takes twice the time to run. I get the answer to query 1 in 1 second and 2 in 2 seconds.
And this is AN EXTREMELY simple case... all I'm doing is casting values. Imagine if you have to join to it like you want to. That's really the worst case.
Now think of what the optimizer is completely unable to do when you hide things in a function.
When you do an IN, sometimes that far faster to do as a join. If certain conditions are true, the optimizer will do that for you. It will convert the IN to a JOIN. But because you've disguised the select inside a function, it can no longer determine if the conditions are ripe. You've FORCED the optimizer to do something sub-optimally.
One key statistic the optimizer relies on is rowcount. Is it one row or 1 billion. It knows from stats on the tables and the indexes. There are no stats on your function.
You can put them there, it possible to hint the cardinality, I'm not saying you can't, but why? Why would you want to? Seemingly you're using the function because you're a diligent programmer who has been told his whole life to factor redundant code into functions.
Those rules in your head, almost none apply to SQL. The optimizer is not a compiler. It can't Inline your function. Only you can help your optimizer get the best plan.