1. 程式人生 > >專案開發之儲存過程發生的那些事

專案開發之儲存過程發生的那些事

前言   

       之前在專案開發過程中,需要有一步操作就是使用儲存過程刪除一系列相關的表,再使用mybatis呼叫該儲存過程,輸入引數為家人賬號,型別為String,資料庫表結構中,該賬號欄位型別為varchar2,再實操的過程中,沒有發生錯誤,可能是輸入引數雖然傳入的是String型別,但是該賬號內容全部為數字,因為在執行過程中就報“ORA-01722: 無效數字”異常了。         

原因分析

         輸入引數雖然是字串型別,但是內容均為數字,在執行儲存過程字串拼接時,如果是使用“||”符號進行拼接,那麼拼接後的sql是沒有單引號的,也就是比如儲存過程中某條語句:execu_sql := 'delete from userinfo where account = ' ||account;(execu_sql為在儲存過程定義的變數,為varchar(2000),":="為賦值操作,相當於把這條sql賦值給execu_sql這個表變數進行儲存),但是執行完成後,execu_sql這個變數內容為:"delete from userinfo where account = XXXXXX",我們知道,把這個sql執行,肯定會報無效數字異常的,因此異常就是這樣出現的,因為oracle有隱式轉換機制,如果你傳入的雖然是String型別的變數,但是如果變數的內容全部都會數字,那麼oracle預設會將該String型別變數轉化為數字,那麼執行時就會報錯了。

解決方案

        那麼我們在實操的過程中就要動態的拼接單引號了,可以使用ASCII 編碼,單引號的ASCII 編碼我39,那麼儲存過程sql可以這樣寫:execu_sql := 'delete from userinfo where account = '||chr(39)||account||chr(39);這樣就不會出錯了。

 

loop迴圈使用

       loop迴圈中可以迴圈呼叫儲存過程而不會報錯,例如:

     --迴圈建立明日的表
     loop
   --抽取方法,檢查今天的表有無建立,如果沒有就建立
   create_gps_day_table(current_datetime);
   
   --抽取方法,檢查今天表序列是否建立,如果沒有就建立
   create_gps_day_seq(current_datetime);
   
   current_datetime := current_datetime+1;
   --當中間天數小於結束月份天數跳出迴圈
    exit when current_datetime>end_datetime;
    end loop; 

    但是如果loop迴圈中迴圈執行多條sql操作,則迴圈會失效,例如:

     loop    
       execu_sql := 'alter table '||table_names||' add(datas clob)';
       execute immediate execu_sql;
      
       execu_sql := 'update '||table_names||' set datas = data';
       execute immediate execu_sql;
   
       execu_sql := 'alter table '||table_names||' drop column data'; 
       execute immediate execu_sql;
   
       execu_sql := 'alter table '||table_names||' rename column datas to data';
       execute immediate execu_sql;
   
       start_datetime := start_datetime+1;
   
       exit when start_datetime>current_datetime;
     end loop;  

     或者一條儲存過程中寫多個迴圈,並且迴圈中執行一條sql操作,則第一條迴圈能成功,而後續迴圈均報:

ORA-00942:表或檢視不存在錯誤。例如:

     loop    
       table_names := 'tb_app_time_'||start_datetime;
 
       execu_sql := 'alter table '||table_names||' add(datas clob)';
       execute immediate execu_sql;
   
       start_datetime := start_datetime + 1;
   
       exit when start_datetime>end_datetime;
     end loop;  
 
      loop          
       table_names := 'tb_app_time_'||start_datetime;
   
       execu_sql := 'update '||table_names||' set datas = data';
       execute immediate execu_sql;
   
       start_datetime := start_datetime+1;
   
       exit when start_datetime>end_datetime;
     end loop;