转换动态查询以在Oracle 11g中使用绑定变量

时间:2015-04-23 13:04:12

标签: oracle stored-procedures oracle11g

我有一个动态搜索查询,我想转换为使用绑定变量。查询的动态部分位于where子句中,并使用一系列if语句构建一个字符串,该字符串与查询字符串的其余部分连接在一起。然后在for语句的open子句中使用该查询,结果集是返回参数。我真的不确定如何做到这一点。

这是存储过程:

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;

3 个答案:

答案 0 :(得分:1)

最好的方法是避免这种头痛。 ' 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;

答案 1 :(得分: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 :(得分:0)

每个对PL / SQL变量的引用实际上都是绑定变量。

您可以查看此asktom链接 https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:2320123769177

并检查"动态SQL"来自此链接http://www.akadia.com/services/ora_bind_variables.html