在 Oracle 11g 中转换动态查询以使用绑定变量
Posted
技术标签:
【中文标题】在 Oracle 11g 中转换动态查询以使用绑定变量【英文标题】:Converting a dynamic query to use bind variables in Oracle 11g 【发布时间】:2015-04-23 13:04:12 【问题描述】:我有一个动态搜索查询,我想将其转换为使用绑定变量。查询的动态部分在where
子句中,并使用一系列if
语句来构建连接到查询字符串的其余部分的字符串。然后在open
statement 的for
子句中使用该查询,结果集是返回参数。我不太确定如何做到这一点。
这是存储过程:
PROCEDURE run_search(i_unit_id IN lu_unit.fsu_id%TYPE,
i_equipment IN tbl_component.component%TYPE,
i_equipment_status IN tbl_component.equipment_status%TYPE,
i_equipment_type IN tbl_component.equipment_type%TYPE,
i_equipment_subtype IN tbl_component.equipment_sub_type%TYPE,
i_system_id IN tbl_component.system_id%TYPE,
i_association_code IN tbl_component_assc_code.assc_code%TYPE,
i_manufacturer IN lu_component_manu_model.equipment_manufacturer%TYPE,
i_manumodel IN lu_component_manu_model.equipment_model%TYPE,
o_results OUT sys_refcursor) AS
v_query VARCHAR2(32767) := '';
v_where VARCHAR2(32767) := ' 1= 1';
BEGIN
IF i_unit_id IS NOT NULL THEN
v_where := v_where || ' AND unit_id=''' || i_unit_id ||''' ';
END IF;
IF i_equipment IS NOT NULL THEN
v_where := v_where || ' AND lower(component) LIKE ''%' || lower(i_equipment) ||'%'' ';
END IF;
IF i_equipment_status IS NOT NULL THEN
v_where := v_where || ' AND equipment_status=''' || i_equipment_status ||''' ';
END IF;
IF i_equipment_type IS NOT NULL THEN
v_where := v_where || ' AND equipment_type=''' || i_equipment_type ||''' ';
END IF;
IF i_equipment_subtype IS NOT NULL THEN
v_where := v_where || ' AND equipment_sub_type=''' || i_equipment_subtype ||''' ';
END IF;
IF i_system_id IS NOT NULL THEN
v_where := v_where || ' AND system_id=''' || i_system_id || ''' ';
END IF;
IF i_association_code IS NOT NULL THEN
v_where := v_where || ' AND EXISTS ( select null from tbl_component_assc_code where assc_code = ''' || i_association_code || ''' and component_id = vcs.component_id )';
END IF;
IF i_manufacturer IS NOT NULL THEN
v_where := v_where || ' AND equipment_manufacturer=''' || i_manufacturer || ''' ';
END IF;
IF i_manuModel IS NOT NULL THEN
v_where := v_where || ' AND equipment_model=''' || i_manuModel || ''' ';
END IF;
v_query :=
' SELECT rownum, results.* '
||' FROM '
||' ( SELECT '
||' count(*) OVER () ' || ' as total_results, '
||''
||' site_id, site_display_name, '
||' unit_id, unit_display_name, '
||' system_id, system_display_name, '
||' component_id, component, component_description, equipment_description, '
||' equipment_status, equipment_model, equipment_serial_number, equipment_type, equipment_sub_type, '
||' template_ids '
||''
||' FROM vw_component_search '
||' WHERE ' || v_where
||' ORDER BY unit_display_name, component '
||' ) results '
;
OPEN o_results FOR v_query;
END run_search;
【问题讨论】:
看到这个***.com/questions/29774122/… 【参考方案1】:您可以在不动态创建查询的情况下编写查询,因此您可以包含所有参数并忽略 NULL
的那些参数(请对其进行分析以测试与动态查询相比是否存在任何性能问题):
PROCEDURE run_search(i_unit_id IN lu_unit.fsu_id%TYPE,
i_equipment IN tbl_component.component%TYPE,
i_equipment_status IN tbl_component.equipment_status%TYPE,
i_equipment_type IN tbl_component.equipment_type%TYPE,
i_equipment_subtype IN tbl_component.equipment_sub_type%TYPE,
i_system_id IN tbl_component.system_id%TYPE,
i_association_code IN tbl_component_assc_code.assc_code%TYPE,
i_manufacturer IN lu_component_manu_model.equipment_manufacturer%TYPE,
i_manumodel IN lu_component_manu_model.equipment_model%TYPE,
o_results OUT sys_refcursor)
AS
BEGIN
OPEN o_results FOR
SELECT rownum,
results.*
FROM ( SELECT count(*) OVER () as total_results,
site_id,
site_display_name,
unit_id,
unit_display_name,
system_id,
system_display_name,
component_id,
component,
component_description,
equipment_description,
equipment_status,
equipment_model,
equipment_serial_number,
equipment_type,
equipment_sub_type,
template_ids
FROM vw_component_search
WHERE ( i_unit_id IS NULL
OR unit_id= i_unit_id )
AND ( i_equipment IS NULL
OR lower(component) LIKE '%' || lower(i_equipment) || '%' )
AND ( i_equipment_status IS NULL
OR equipment_status= i_equipment_status )
AND ( i_equipment_type IS NULL
OR equipment_type= i_equipment_type )
AND ( i_equipment_subtype IS NULL
OR equipment_sub_type= i_equipment_subtype )
AND ( i_system_id IS NULL
OR system_id= i_system_id )
AND ( i_association_code IS NULL
OR EXISTS ( select null
from tbl_component_assc_code
where assc_code = i_association_code
and component_id = vcs.component_id ) )
AND ( i_manufacturer IS NULL
OR equipment_manufacturer= i_manufacturer )
AND ( i_manuModel IS NULL
OR equipment_model= i_manuModel )
ORDER BY unit_display_name, component
) results;
END run_search;
(我没有编译上面的代码 - 所以可能会有一些错误)。
【讨论】:
【参考方案2】:最好的办法是完全避免这种头痛。 'SP 返回结果集' 在 MSSQL2000 等不良遗留事物中是一种常见的做法,但在 Oracle 中是不必要且值得怀疑的。
如果你想这样做,我建议你这样做:
procedure MakeGarbage(value_mask varchar2) return sys_refcursor is
cur integer;
stmt varchar2(32000 byte);
type TParamTable is table of varchar2(1000) index by varchar2(20);
params TParamTable;
i varchar2(20);
begin
stmt := 'select * from table where 1 = 1 ';
if value_mask is not null then
stmt := stmt || ' and value like :value_mask ';
params('value_mask') := value_mask;
end if;
...
cur := dbms_sql.create_cursor;
dbms_sql.open_cursor(cur, stmt, dbms_sql.native);
i := params.first;
while i is not null loop
dbms_sql.bind_variable(i, params(i));
i := params.next(i);
end loop;
return dbms_sql.to_ref_cursor(cur);
end;
【讨论】:
终于找到了一个正确理解如何在 Oracle 中创建动态语句的人。你在这里找不到这么多。 你能否更好地解释这个答案,因为我很难理解。 似乎是一个绝妙的答案。我希望这个答案的作者可以多解释一点,以便我(作为初学者)可以更好地理解。【参考方案3】:对 PL/SQL 变量的每个引用实际上都是一个绑定变量。
你可以查看这个 asktom 链接 https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:2320123769177
并从此链接http://www.akadia.com/services/ora_bind_variables.html检查“动态SQL”
【讨论】:
以上是关于在 Oracle 11g 中转换动态查询以使用绑定变量的主要内容,如果未能解决你的问题,请参考以下文章