Ewa*_*anw 5 oracle plsql oracle10g
我有一个带有联合的大量 SQL 语句,其中代码不断被重用。我希望找出是否有一种方法可以重用单个绑定变量,而无需多次重复“使用”变量。
下面的代码返回“并非所有变量都绑定”,直到我将“USING”行更改为“USING VAR1,VAR2,VAR1;”
我希望避免这种情况,因为我在这两种情况下都指的是 :1 - 有什么想法吗?
declare
var1 number :=1;
var2 number :=2;
begin
execute immediate '
select * from user_objects
where
rownum = :1
OR rownum = :2
OR rownum = :1 '
using var1,var2;
end;
/
Run Code Online (Sandbox Code Playgroud)
编辑:有关其他信息,我正在使用动态 SQL,因为我还生成了一组 where 条件。
我不太擅长 SQL 数组(我在代码中使用了游标,但我认为这会使问题变得过于复杂),但伪代码是:
v_where varchar2(100) :='';
FOR i in ('CAT','HAT','MAT') LOOP
v_where := v_where || ' OR OBJECT_NAME LIKE ''%' || i.string ||'%''
END;
v_where := ltrim(v_where, ' OR');
Run Code Online (Sandbox Code Playgroud)
然后将上面的 SQL 修改为:
execute immediate '
select * from user_objects
where
rownum = :1
OR rownum = :2
OR rownum = :1 AND ('||V_WHERE||')'
using var1,var2;
Run Code Online (Sandbox Code Playgroud)
您可能会考虑一些选项,尽管它们可能需要更改,无论是执行 SQL 语句的方式还是更改 SQL 语句本身。
DBMS_SQL代替EXECUTE IMMEDIATE-- DBMS_SQL(请参阅http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_sql.htm)比 更难使用EXECUTE IMMEDIATE,但可以让您更好地控制过程——包括能力(通过DBMS_SQL.BIND_VARIABLE和DBMS_SQL.BIND_ARRAY) 按名称而不是按位置绑定。EXECUTE IMMEDIATE与WITH子句一起使用——您可以重构您的查询以使用WITH从一开始就在子查询中收集绑定变量的子句,然后在需要时加入子查询(而不是直接引用绑定变量)。它可能看起来像这样with your_parameters as
(select :1 as p1, :2 as p2 from dual)
select *
from your_table, your_parameters
where your_table.some_column1 = your_parameters.p1
and your_table.some_column2 <= your_parameters.p1
and your_table.some_column3 = your_parameters.p2
Run Code Online (Sandbox Code Playgroud)
这可能会影响查询的性能,但它可能是一个可以接受的折衷方案。
编辑:如果您使用动态 SQL 是因为您OR在编辑中发布的条件数量可变,则可以通过执行以下操作之一来避免使用动态 SQL:
OR条件来自表(或查询) ——连接到该表(或查询)而不是使用OR条件列表。例如,如果CAT,帽子和MAT是在一个名为列YOUR_CRITERIA在一个表名为YOUR_CRITERIA_TABLE您可以添加YOUR_CRITERIA_TABLE到FROM子句和替换OBJECT_NAME LIKE '%CAT% OR OBJECT_NAME LIKE '%MAT% OR OBJECT_NAME LIKE '%HAT% OR OBJECT_NAME LIKE '%MAT%中WHERE有类似条款OBJECT_NAME LIKE '%' || YOUR_CRITERIA_TABLE.YOUR_CRITERIA || '%'.CREATE TYPE...IS TABLE OF)而不是全局临时表。您可以创建或拥有嵌套表类型,或使用内置表类型,例如SYS.ODCIVARCHAR2LIST. 在 PL/SQL 中,您将填充这种类型的变量,然后像第 1 项中的“真实”表一样使用它。第 3 项的示例可能如下所示:
DECLARE
tblCriteria SYS.ODCIVARCHAR2LIST;
BEGIN
tblCriteria := SYS.ODCIVARCHAR2LIST();
-- In "real" code you might populate the nested table in a loop.
-- This example populates it explicitly so that it will compile. For the
-- purpose of the example, we could have populated the nested table in
-- a single statement:
-- tblCriteria := SYS.ODCIVARCHAR2LIST('CAT', 'HAT', 'MAT');
tblCriteria.EXTEND(1);
tblCriteria(tblCriteria.LAST) := 'CAT';
tblCriteria.EXTEND(1);
tblCriteria(tblCriteria.LAST) := 'HAT';
tblCriteria.EXTEND(1);
tblCriteria(tblCriteria.LAST) := 'MAT';
FOR rec IN
(
SELECT
USER_OBJECTS.*
FROM
USER_OBJECTS,
TABLE(tblCriteria) YOUR_NESTED_TABLE
WHERE
USER_OBJECTS.OBJECT_NAME LIKE '%' || YOUR_NESTED_TABLE.COLUMN_VALUE || '%'
)
LOOP
-- Do something. For example, print out the object name.
DBMS_OUTPUT.PUT_LINE(rec.OBJECT_NAME);
END LOOP;
END;
Run Code Online (Sandbox Code Playgroud)