1. 程式人生 > >Oracle execute immediate 拼接條件 引數化

Oracle execute immediate 拼接條件 引數化

最近在將專案的資料庫改成Oracle,本人對Oracle也是一無所知,邊做邊摸索。

在使用 execute immediate 動態執行SQL分頁,發現網上很多例子都是通過引數值直接拼接成SQL來執行。

對於Oracle新手來說,好像Oracle沒有類似 SQLServer exec sp_executesql 引數化查詢這樣的功能。

例如:

declare
  p_accountnum  varchar2(100);
  p_groupid     integer;
  p_recordcount integer;
  p_select      varchar2(500);
begin
  p_accountnum := 'gh_xxxxxxxxx';
  p_groupid    := 109;
  p_select     := 'select count(*) from wxuser where 1=1 and accountnum =''' ||  p_accountnum || ''' and groupid =' || p_groupid;
  execute immediate p_select into p_recordcount;
  dbms_output.put_line(p_recordcount);
end;

這樣很明顯的一樣問題,如果引數p_accountnum存在SQL特殊字元,就會出現SQL注入了。當然你也可以在專案程式中對SQL特殊字元進行過濾。

但有時候在寫程式中,可能因各種不小心會忘記對SQL特殊字元過濾,所以最可靠的辦法就是直接將值引數化,不通過引數值直接拼接成SQL來執行。

這是我寫的一個儲存過程,希望可以幫到一些Oracle新手。

procedure SelectByWhere(p_accountnum  in varchar2,
                          p_groupid     in integer,
                          p_pageindex   in integer,
                          p_pagesize    in integer,
                          p_recordcount out integer,
                          v_result      out pack_wxuser.cur_type) is
    v_select varchar2(500);
    v_where  varchar2(500);
  begin
    v_where := ' where 1=1';
    if p_accountnum is not null and length(p_accountnum) > 0 then
      begin
        v_where := v_where || ' and accountnum = :a';
      end;
    else
      begin
        v_where := v_where || ' and ((1=1) or :a is null)';
      end;
    end if;
    if p_groupid is not null and p_groupid > 0 then
      begin
        v_where := v_where || ' and groupid = :b ';
      end;
    else
      begin
        v_where := v_where || ' and ((1=1) or :b is null)';
      end;
    end if;
    v_select := 'select count(*) from wxuser' || v_where;
    dbms_output.put_line(v_select);
    execute immediate v_select
      into p_recordcount
      using p_accountnum, p_groupid;
    v_where := v_where || ' order by subscribe_time desc';
    if p_pageindex is not null and p_pageindex > 0 and
       p_pagesize is not null and p_pagesize > 0 then
      begin
        v_select := 'select t.* ,g.groupname groupname from (select w.*, rownum as rowno from (select * from wxuser' ||
                    v_where || ') w where rownum <=' ||
                    (p_pageindex * p_pagesize) ||
                    ') t left join wxgroup g on t.groupid=g.groupid where t.rowno >=' ||
                    ((p_pageindex - 1) * p_pagesize);
      end;
    else
      begin
        v_select := 'select t.*,g.groupname groupname from ( select * from wxuser' ||
                    v_where ||
                    ' ) t left join wxgroup g on t.groupid=g.groupid';
      end;
    end if;
    dbms_output.put_line(v_select);
    open v_result for v_select
      using p_accountnum, p_groupid;
  end;