问题描述
|
我想创建一个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部分变为静态的示例:
-- 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;
解决方法
抱歉,为什么需要这样做?通过引入一个根据参数列表返回不同类型的数据/表的函数,您似乎使事情复杂化了。 imo非常令人困惑。此外,您必须在某处完成工作,只是要将其隐藏在此函数中(在内部,如果param1 = this则x如果param1 = that则y ...)
此外,即使您确实实现了游标功能(甚至是流水线操作),在这种情况下也不是一个好主意,因为您将迫使Oracle进行不一定要执行的工作(忽略所有上下文)。现在切换)。为了获得计数,您需要Oracle逐行记录每个结果,然后计数。很多时候,Oracle可以进行快速的全索引扫描以获得计数(当然取决于查询)。而且,如果在缓冲区高速缓存中找到了块,通常多次运行相同的查询将不需要每次都完成所有工作。我想让您使用直接SQL与使用返回游标的函数多次运行计数。您可能会感到惊讶。据我所知(对此进行检查),新的11g函数结果缓存不适用于流水线函数或返回ref游标的函数(以及其他问题,例如由于依赖表而导致的无效)。
因此,我要说的是为什么不这样做:从...选择count(1)到v_variable中;
如果您想隐藏和模块化,那么只需知道您可能丢失的内容。
, 您可能要在function1中打开查询,然后将查询的结果作为表传递给function2,然后向该“ table”添加where子句
在这种情况下,您需要将function1重写为流水线表函数
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
, 您可以使用Oracle表达式过滤器对表达式进行编译时检查。
它可能比其他解决方案更复杂,但是如果您确实需要验证条件,则可能会有所帮助。