專案開發之儲存過程發生的那些事
前言
之前在專案開發過程中,需要有一步操作就是使用儲存過程刪除一系列相關的表,再使用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;