我想创建一个Oracle包,其中有一个执行某些动态SQL的过程。如果我使用EXECUTE IMMEDIATE
进行动态操作,这没有问题,但如果查询的静态部分可以编码为静态(以便进行编译时检查),那就更好了。
完全动态查询的示例:
-- v_stmt is built dynamically.
v_stmt := 'SELECT count(*) FROM <here some joins> WHERE <here some conditions>';
EXECUTE IMMEDIATE v_stmt
USING v_param1, v_param2
RETURNING INTO v_count;
我试图使FROM-part静态的例子:
-- v_stmt is built dynamically.
v_stmt := 'SELECT count(*) FROM my_package.my_function(:param1, :param2) WHERE <here some conditions>';
EXECUTE IMMEDIATE v_stmt
USING v_param1, v_param2
RETURNING INTO v_count;
FUNCTION my_function(
i_param1 IN VARCHAR2,
i_param2 IN NUMBER
)
RETURN SYS_REFCURSOR
AS
v_cursor SYS_REFCURSOR;
BEGIN
-- Open a cursor for different queries depending on params.
IF i_param2 = 1 THEN
OPEN v_cursor FOR <some static query>;
ELSE
OPEN v_cursor FOR <some other static query>;
END IF;
RETURN v_cursor;
END;
这不起作用,因为无法从SYS_REFCURSOR中选择(至少这是我在Google上找到的)。
有没有办法达到这个目标?
编辑:根据要求,以下是一些示例:
静态查询:
SELECT a.*, ca.CUS_ID FROM adresses a INNER JOIN customer_adresses ca ON (ca.adr_id = a.adr_id);
SELECT p.*, cp.CUS_ID FROM persons p INNER JOIN customer_persons cp ON (cp.per_id = p.per_id);
然后像以下示例一样动态扩展它们:
-- Checks if there is an adress in the customer where the zip is null.
SELECT count(*) FROM <static adresses query> q WHERE q.cus_id = :param1 AND a.zip IS NULL;
-- Checks if there is at least one person in the customer.
SELECT count(*) FROM <static persons query> q WHERE q.cus_id = :param1;
答案 0 :(得分:2)
抱歉,为什么需要这样做?通过引入一个根据参数列表返回不同类型的数据/表的函数,您似乎已经结束了复杂化。非常令人困惑的imo。此外,你必须在某个地方做这项工作,你只是想在这个函数中隐藏它(如果param1 =这个那么x,如果param1 =然后是y ......)
此外,即使你确实实现了一个游标函数(甚至是流水线),在这种情况下也是一个坏主意,因为你要强迫Oracle完成它不一定需要做的工作(忽略所有现在进行上下文切换)。为了得到一个计数,你可以让Oracle获取每一行的结果,然后计算。很多时候,Oracle可以进行快速全索引扫描来获取计数(当然,取决于查询)。并且,如果在缓冲区缓存中找到块,则每次运行多次相同的查询将不需要执行所有工作。我要求你使用直接SQL和使用返回游标的函数多次运行计数。你可能会感到惊讶。据我所知(请看这个)新的11g函数结果缓存不适用于流水线函数或返回引用游标的函数(以及由于依赖表而导致的其他问题)。
所以,我所说的是为什么不这样做:从...中选择count(1)到v_variable;
如果你想隐藏和模块化,那就知道你可能会失去什么。
答案 1 :(得分:1)
您可能希望在function1中打开一个查询,然后将其结果作为一个表格传递给function2,然后将该where子句添加到此“table”
在这种情况下,您需要将function1重写为pipelined table function
v_stmt := 'SELECT count(*) FROM table(my_package.my_function(:param1, :param2)) WHERE <here some conditions>';
EXECUTE IMMEDIATE v_stmt
USING v_param1, v_param2
RETURNING INTO v_count;
CREATE TYPE object_row_type AS OBJECT (
OWNER VARCHAR2(30),
OBJECT_TYPE VARCHAR2(18),
OBJECT_NAME VARCHAR2(30),
STATUS VARCHAR2(7)
);
CREATE TYPE object_table_type AS TABLE OF object_row_type;
FUNCTION my_function(
i_param1 IN VARCHAR2,
i_param2 IN NUMBER
)
RETURN object_table_type PIPELINED AS
BEGIN
答案 2 :(得分:0)
您可以使用Oracle expression filter对表达式进行编译时检查。
它可能比其他解决方案更复杂,但如果你真的需要验证你的条件,它会有所帮助。