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

在Oracle 11g中将动态查询转换为使用绑定变量,oracle,stored-procedures,oracle11g,Oracle,Stored Procedures,Oracle11g,我有一个动态搜索查询,我想将其转换为使用绑定变量。查询的动态部分位于where子句中,并使用一系列if语句构建一个字符串,该字符串连接到查询字符串的其余部分。然后在open语句的for子句中使用该查询,结果集是返回参数。我真的不知道如何做到这一点 以下是存储过程: PROCEDURE run_search(i_unit_id IN lu_unit.fsu_id%TYPE, i_equipment IN tbl_comp

我有一个动态搜索查询,我想将其转换为使用绑定变量。查询的动态部分位于
where
子句中,并使用一系列
if
语句构建一个字符串,该字符串连接到查询字符串的其余部分。然后在
open
语句的
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;

最好的办法就是避免这种头痛。”SP returning resultset’是MSSQLS2000等劣质遗留产品中的常见做法,但在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;

您可以在不动态创建查询的情况下编写查询,以便包含所有参数,而忽略那些
NULL
(请对其进行分析,以测试与动态查询相比是否存在任何性能问题):


(我没有编译上面的代码-因此可能会有一些错误)。

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

你可以检查这个asktom链接


从这个链接中勾选“动态SQL”

最后看看这个家伙,他完全了解如何在Oracle中创建动态语句。你在这里找不到这么多。你能不能把这个答案解释得更清楚一点,因为我很难理解。这似乎是一个很好的答案。我希望这个答案的作者能多解释一点,以便我(作为初学者)能更好地理解。
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;