1. 程式人生 > >Oracle動態SQL語句

Oracle動態SQL語句

在使用ODP.NET進行Oracle程式設計時,有時候SQL語句非常複雜,需要採用動態構造查詢語句的情況,有兩種方法可以構造動態的SQL語句,並執行返回結果集。

1、在資料訪問層構造SQL語句

例如下面的語句,將構造完整的SQL語句賦值給CommandText,再傳遞到資料庫進行執行,返回結果集。

loadCommand.CommandType = CommandType.Text
   loadCommand.CommandText = "Select * From Users"

   dataAdapter .SelectCommand = loadCommand
   dataAdapter . Fill(data)

   dataAdapter .SelectCommand = loadCommand
   dataAdapter . Fill(data)

該方法需要將整個SQL的構造過程放在DataAccess層,業務邏輯發生變化,修改不方便,而且每次查詢需要傳遞給資料庫很長的查詢字串,傳遞引數的效率也不高。

2、在儲存過程中構造動態SQL語句並執行

 以下為一個完整的事例(經過刪減),其中RefCursor 為自定義遊標型別

PROCEDURE G_Search(P_YearNO      INNUMBER,
                              P_ControlType 
INNUMBER,
                              P_Progress    
INCHAR,
                              P_DepartID    
INVARCHAR2,
                              P_ProjectName 
IN NVARCHAR2,
                              C_Projects    OUT RefCursor) 
IS
        e_ErrInterruption EXCEPTION;
        v_ErrID       
NUMBER--
Variable to hold the errorlog id        v_ErrCode     NUMBER--Variable to hold the error message code        v_ErrText     VARCHAR2(512); --Variable to hold the error message text        v_ErrProc     VARCHAR2(50) :='G_Search';
        v_DepartID    
VARCHAR2(16);
        v_ProjectName NVARCHAR2(
128);
        v_SQL         
VARCHAR2(512);
        v_Where       
VARCHAR2(256);
    
BEGIN
    
        v_SQL   :
='SELECT PROJECTID, PARENTID, PROJECTNAME ';
        v_SQL   :
= v_SQL ||' FROM PROJECTS A';
        v_Where :
=' Where';
    
        
-- 年度IF P_YearNO <9999THEN
            v_Where :
= v_Where ||'  A.YearNO = '|| P_YearNO ||' And';
        
ELSE
            v_Where :
= v_Where ||'  A.YearNO < '|| P_YearNO ||' And';
        
ENDIF;
        
-- 控制類別IF P_ControlType =9THEN
            v_Where :
= v_Where ||' A.ControlType < 9 And';
        
ELSE
            v_Where :
= v_Where ||' A.ControlType = '|| P_ControlType ||' And';
        
ENDIF;
        
-- 進度IF P_Progress <'Z'THEN
            v_Where :
= v_Where ||' A.Progress = '''|| P_Progress ||''' And';
        
ELSE
            v_Where :
= v_Where ||' A.Progress < '''|| P_Progress ||''' And';
        
ENDIF;
    
        
IF TRIM(P_DepartID) <>'%'THEN
            v_Where :
= v_Where ||' A.DepartID = '''|| P_DepartID ||''' And';
        
ELSE
            v_Where :
= v_Where ||' A.DepartID Like '''|| P_DepartID ||''' And';
        
ENDIF;
        
--專案名稱        v_ProjectName := NVL(P_ProjectName,
                             
'%');
        
IF v_ProjectName <>'%'THEN
           v_ProjectName :
='%'|| P_ProjectName ||'%';
        
ENDIF;
        v_Where :
= v_Where ||' A.ProjectName Like '||''''|| v_ProjectName ||''' And';
          
    
       v_SQL :
= v_SQL || v_Where;
    
        
OPEN C_PROJECTS FOR v_SQL;
    
        
--COMMIT;    EXCEPTION
        
--根據需要定義錯誤異常WHEN OTHERS THEN--ROLLBACK; v_ErrID   := SQLCODE;
            v_ErrText :
= SQLERRM;
            raise_application_error(v_ErrID,
                                    v_ErrText);
    
END G_Search;


該方法只需要傳遞給儲存過程一些引數,使用遊標返回資料。引數傳遞效率較高,而且業務邏輯在儲存過程中,調整比較方便。該方法關鍵的在下面的語句:
Open C_Projects For v_SQL;
它直接使用遊標開啟構造的查詢字串即可。

注意事項:

A)、構造的SQL語句最後不能帶有分號;
B)、SQL語句中對於字元和字串的條件需要用單引號包括起來
C)、最重要:動態SQL語句需要防止SQL注入攻擊。我們採用最簡單的辦法,只允許一個關鍵詞查詢,將關鍵詞中的所有空格去掉。對於多關鍵詞,需要將他們用空格拆開,再構造。