我有一个动态 PL/SQL,它将根据用户输入的搜索条件构建 SELECT 语句,喜欢:
l_sql := 'SELECT * INTO FROM TABLEA WHERE 1=1 ';
IF in_param1 IS NOT NULL THEN
l_sql := l_sql || 'AND column1 = in_param1 ';
END IF;
IF in_param2 IS NOT NULL THEN
l_sql := l_sql || 'AND column2 = in_param2 ';
END IF;
...................................
IF in_paramXX IS NOT NULL THEN
l_sql := l_sql || 'AND columnXX = in_paramXX ';
END IF;
为了减少硬解析开销,我考虑使用绑定变量。然而,向绑定变量提供实际值时管理起来很困难,因为绑定变量和生成的 SELECT 语句的组合太多。我无法使用 http://www.dba 引入的 DBMS_SESSION.set_context() 方法-oracle.com/plsql/t_plsql_dynamic_binds.htm 因为我的帐户无权使用这个包。此外,我希望生成的 SQL 仅包含用户未留空的字段的条件。所以我无法将动态 SQL 更改为类似的内容
SELECT * INTO FROM TABLEA WHERE 1=1
and ( in_param1 is NULL or column1 = in_param1)
and ( in_param2 is NULL or column2 = in_param2)
...............................................
and ( in_paramXX is NULL or columnXX = in_paramXX)
所以,我想尝试使用 DBMS_SQL 方法。任何人都可以举一个关于如何使用 DBMS_SQL 调用带有绑定变量的动态 SQL 的示例吗?特别是,我怎样才能获得从 DBMS_SQL.execute() 执行到 SYS_REFCURSOR 的结果,例如:
open refcursor for select .... from
我使用的 oracle 版本是 10g,并且 oracle 10g 似乎没有 DBMS_Sql.To_Refcursor()
I have a dynamic PL/SQL that will construct the SELECT statement based on what the searching criteria input from the users,likes:
l_sql := 'SELECT * INTO FROM TABLEA WHERE 1=1 ';
IF in_param1 IS NOT NULL THEN
l_sql := l_sql || 'AND column1 = in_param1 ';
END IF;
IF in_param2 IS NOT NULL THEN
l_sql := l_sql || 'AND column2 = in_param2 ';
END IF;
...................................
IF in_paramXX IS NOT NULL THEN
l_sql := l_sql || 'AND columnXX = in_paramXX ';
END IF;
To reduce the hard parse overhead , I consider to use the binding variables. However , it is difficult to manage when supplying the actual values to the binding variables as there are so many binding variables and combination of the generated SELECT statement . I cannot use the method of DBMS_SESSION.set_context() introduced at http://www.dba-oracle.com/plsql/t_plsql_dynamic_binds.htm because my account has no right to use this package. Besides , I want the generated SQL only contains the conditions on the fields that the user did not leave empty. So I cannot change the dynamic SQL to something likes
SELECT * INTO FROM TABLEA WHERE 1=1
and ( in_param1 is NULL or column1 = in_param1)
and ( in_param2 is NULL or column2 = in_param2)
...............................................
and ( in_paramXX is NULL or columnXX = in_paramXX)
So , I want to try to use the DBMS_SQL method .Can anyone give an example about how to use DBMS_SQL to call dynamic SQL with binding variables? Especially , how can I get the result executed from DBMS_SQL.execute() to the SYS_REFCURSOR , something like :
open refcursor for select .... from
The oracle version that I use is 10g and it seems that the oracle 10g does not have DBMS_Sql.To_Refcursor()
发布评论
评论(2)
在您的 Oracle 版本中,您可以对查询应用一些技巧来做到这一点。这个想法是使用以下形式的查询:
然后执行它:
它的工作原理是使用 DUAL 为每个参数生成一个假行,然后将该假行内部连接到您的真实查询(没有任何过滤器)仅使用您想要应用的过滤器。这样,您就可以在
params
子查询的SELECT
列表中拥有固定的绑定变量列表,但可以通过修改之间的联接条件来控制应用哪些过滤器params
和您的真实查询。因此,如果您有这样的情况:
如果您只想过滤
first name
,则可以构造以下查询,如果您想同时过滤
first_name
和last_name
并且在每种情况下您都会执行
使用
where rownum > 对于性能非常重要0
与DUAL
,因为它强制 Oracle“具体化”子查询。这通常会使DUAL
停止干扰查询的其余部分。无论如何,您应该检查执行计划以确保 Oracle 没有做错任何事情。In your Oracle version you can apply some tricks to your query in order to do this. The idea is to use a query in the following form:
then execute it with:
It works by using
DUAL
to generate a fake row with every single param, then inner joining this fake row to your real query (without any filters) using only the filters you want to apply. This way, you have a fixed list of bind variables in theSELECT
list of theparams
subquery, but can control which filters are applied by modifying the join condition betweenparams
and your real query.So, if you have something like, say:
you can construct the following query if you just want to filter on
first name
and this if you want to filter on both
first_name
andlast_name
and in every case you would execute with
It is important for performance to use the
where rownum > 0
withDUAL
as it forces Oracle to "materialize" the subquery. This usually makesDUAL
stop interfering with the rest of the query. Anyway, you should check the execution plans to be sure Oracle is not doing anything wrong.在 10g 中,DBMS_SQL 游标无法更改为引用游标。通过 DBMS_SQL 遍历结果集是曲折的,因为除了循环行之外,您还必须循环遍历行中的列。
这纯粹是出于性能原因吗?如果是这样,我建议您弄清楚实际的执行计划是什么,并对它们使用单独的查询。
例如,假设我正在搜索人员,参数是名字、姓氏。性别、出生日期。该表在 (last_name,first_name) 和 (date_of_birth) 上有索引,因此我只想允许在指定 last_name 或 date_of_birth 时进行查询。
In 10g a DBMS_SQL cursor can't be changed into a Ref Cursor. Going through a result set through DBMS_SQL is tortuous since, as well as looping through the rows, you also have to loop through the columns in a row.
Is that purely for performance reasons ? If so, I suggest you work out what the practical execution plans are and use separate queries for them.
For example, say I'm searching on people and the parameters are first_name, last_name. gender, date_of_birth. The table has indexes on (last_name,first_name) and (date_of_birth), so I only want to allow a query if it specifies either last_name or date_of_birth.