ORACLE中DBMS_SQL的用法
對於一般的select操作,如果使用動態的sql語句則需要進行以下幾個步驟:
open cursor---> parse---> define column---> excute---> fetch rows---> close cursor;
而對於dml操作(insert,update)則需要進行以下幾個步驟:
open cursor---> parse---> bind variable---> execute---> close cursor;
對於delete操作只需要進行以下幾個步驟:
open cursor---> parse---> execute---> close cursor;
www.2cto.com
例一:
create table test(n_id number, v_name varchar2(50), d_insert_date date);
alter table test add constraint pk_id primary key(n_id);
declare
v_cursor number;
v_sql varchar2(200);
v_id number;
v_name varchar2(50);
v_date date;
v_stat number;
begin
v_id := 1;
v_name := '測試 insert';
v_date := sysdate;
v_cursor := dbms_sql.open_cursor; --打開游標
v_sql := 'insert into test(n_id, v_name, d_insert_date) values(:v_id,:v_name,:v_date)';
dbms_sql.parse(v_cursor, v_sql, dbms_sql.native); --解析SQL
dbms_sql.bind_variable(v_cursor, ':v_id', v_id); --綁定變量
dbms_sql.bind_variable(v_cursor, ':v_name', v_name);
dbms_sql.bind_variable(v_cursor, ':v_date', v_date);
v_stat := dbms_sql.execute(v_cursor); --執行
dbms_sql.close_cursor(v_cursor); --關閉游標
commit;
end;
www.2cto.com
例二:
declare
v_cursor number;
v_sql varchar2(200);
v_id number;
v_name varchar2(50);
v_stat number;
begin
v_name := '測試 update';
v_id := 1;
v_cursor := dbms_sql.open_cursor;
v_sql := 'update test set v_name = :v_name, d_insert_date = :v_date where n_id = :v_id';
dbms_sql.parse(v_cursor, v_sql, dbms_sql.native);
dbms_sql.bind_variable(v_cursor, ':v_name', v_name);
dbms_sql.bind_variable(v_cursor, ':v_date', sysdate);
dbms_sql.bind_variable(v_cursor, ':v_id', v_id);
v_stat := dbms_sql.execute(v_cursor);
dbms_sql.close_cursor(v_cursor);
commit;
end;
www.2cto.com
例三:
declare
v_cursor number;
v_sql varchar2(200);
v_id number;
v_stat number;
begin
v_id := 1;
v_sql := 'delete from test where n_id = :v_id';
v_cursor := dbms_sql.open_cursor;
dbms_sql.parse(v_cursor, v_sql, dbms_sql.native);
dbms_sql.bind_variable(v_cursor, ':v_id', v_id);
v_stat := dbms_sql.execute(v_cursor);
dbms_sql.close_cursor(v_cursor);
commit;
end;
例四:
declare
v_cursor number;
v_sql varchar2(200);
v_id number;
v_name varchar2(50);
v_date varchar2(10);
v_stat number;
begin
v_sql := 'select n_id, v_name, to_char(d_insert_date, ''yyyy-mm-dd'') from test';
v_cursor := dbms_sql.open_cursor; --打開游標
dbms_sql.parse(v_cursor, v_sql, dbms_sql.native); --解析游標
dbms_sql.define_column(v_cursor, 1, v_id); --定義列
dbms_sql.define_column(v_cursor, 2, v_name, 50); --注意:當變量為varchar2類型時,要加長度 www.2cto.com
dbms_sql.define_column(v_cursor, 3, v_date, 10);
v_stat := dbms_sql.execute(v_cursor); --執行SQL
loop
exit when dbms_sql.fetch_rows(v_cursor) <= 0; --fetch_rows在結果集中移動游標,如果未抵達末尾,返回1。
dbms_sql.column_value(v_cursor, 1, v_id); --將當前行的查詢結果寫入上面定義的列中。
dbms_sql.column_value(v_cursor, 2, v_name);
dbms_sql.column_value(v_cursor, 3, v_date);
dbms_output.put_line(v_id || ':' || v_name || ':' || v_date);
end loop;
end;
--------------------------------------------------------------------------------------------------
PL/SQL中使用動態SQL
編程
在PL/SQL程序設計過程中,會遇到很多必須使用動態sql的地方,oracle系統所tb提供的DMBS_SQL包可以幫助你解決問題。
(一)介紹
DBMS_SQL系統包提供了很多函數及過程,現在簡要闡述其中使用頻率較高的幾種:
function open_cursor:打開一個動態游標,並返回一個整型;
procedure close_cursor(c in out integer) :關閉一個動態游標,參數為open_cursor所打開的游標;
www.2cto.com
procedure parse(c in integer, statement in varchar2, language_flag in integer):對動態游標所提供的sql語句進行解析,參數C表示游標,statement為sql語句,language-flag為解析sql語句所用oracle版本,一般有V6,V7跟native(在不明白所連database版本時,使用native);
procedure define_column(c in integer, position in integer, column any datatype, [column_size in integer]):定義動態游標所能得到的對應值,其中c為動態游標,positon為對應動態sql中的位置(從1開始),column為該值所對應的變量,可以為任何類型,column_size只有在column為定義長度的類型中使用如VARCHAR2,CHAR等(該過程有很多種情況,此處只對一般使用到的類型進行表述);
function execute(c in integer):執行游標,並返回處理一個整型,代表處理結果(對insert,delete,update才有意義,而對select語句而言可以忽略);
function fetch_rows(c in integer):對游標進行循環取數據,並返回一個整數,為0時表示已經取到游標末端;
procedure column_value(c in integer, position in integer, value):將所取得的游標數據賦值到相應的變量,c為游標,position為位置,value則為對應的變量;
procedure bind_variable(c in integer, name in varchar2, value):定義動態sql語句(DML)中所對應字段的值,c為游標,name為字段名稱,value為字段的值;
以上是在程序中經常使用到的幾個函數及過程,其他函數及過程請參照oracle所提供定義語句dbmssql.sql
(二)一般過程
www.2cto.com
對於一般的select操作,如果使用動態的sql語句則需要進行以下幾個步驟:
open cursor--->parse--->define column--->excute--->fetch rows--->close cursor;
而對於dml操作(insert,update)則需要進行以下幾個步驟:
open cursor--->parse--->bind variable--->execute--->close cursor;
對於delete操作只需要進行以下幾個步驟:
open cursor--->parse--->execute--->close cursor;
(三)具體案例
下面就本人所開發系統中某一程序做分析
該過程為一股票技術曲線計算程序,將數據從即時數據表中取出,並按照計算曲線的公式,tb對這些數據進行計算,並將結果保存到技術曲線表中.
create or replace procedure R_Ma_Main
( www.2cto.com
pid varchar2,
pend varchar2,
pinterval varchar2,
totab varchar2
) is
--定義數組
type Date_type is table of varchar2(12) index by binary_integer;
type Index_type is table of number index by binary_integer;
TempDate Date_Type;--時間數組
TempIndex Index_Type;--股票收盤價數組
TempMa Index_Type;--ma技術曲線數據
cursor1 integer;--游標
cursor2 integer;--游標
rows_processed integer;--執行游標返回
TempInter integer;--參與計算數值個數
TempVal integer;--計算時間類型
TempSql varchar2(500);--動態sql語句
MyTime varchar2(12);--時間
MyIndex number;--數值
MidIndex number;--中間變量
i integer := 999;
j integer;
begin www.2cto.com
TempInter := to_number(substr(pinterval,1,4));
TempVal := to_number(substr(pinterval,5,2));
TempSql := R_GetSql1(pid, pend, TempVal);--得到選擇數據的sql語句
--得到當天的即時數據,並依次保存到數組中
cursor1 := dbms_sql.open_cursor; --創建游標
dbms_sql.parse(cursor1, TempSql, dbms_sql.native); --解析動態sql語句,取兩個字段,時間及價格,其中時間以14位的varchar2表示
dbms_sql.define_column(cursor1, 1, MyTime, 12); --分別定義sql語句中各字段所對應變量
dbms_sql.define_column(cursor1, 2, MyIndex);
rows_processed := dbms_sql.execute(cursor1);
loop
if dbms_sql.fetch_rows(cursor1) > 0 then
begin
dbms_sql.column_value(cursor1, 1, MyTime);
dbms_sql.column_value(cursor1, 2, MyIndex);
TempDate(i) := MyTime;
TempIndex(i) := MyIndex;
i := i - 1;--按倒序的方法填入數組
end;
else
exit;
end if;
end loop;
dbms_sql.close_cursor(cursor1);
--如果取得的數據量不夠計算個數,則跳出程序
if i > 999-TempInter then
goto JumpLess;
end if;
--初始化中間變量
MidIndex := 0;
TempIndex(i) := 0;
for j in i..i+TempInter-1 loop
MidIndex := MidIndex + TempIndex(j);
end loop;
www.2cto.com
--依次對當天數據計算ma值,並保存到ma數組中
for j in i+TempInter..999 loop
MidIndex := MidIndex - TempIndex(j-TempInter) + TempIndex(j);
TempMa(j) := MidIndex/TempInter;
end loop;
if TempVal < 6 then--如果計算的是分鍾跟天的ma技術曲線
begin
cursor2 := dbms_sql.open_cursor;
TempSql := 'insert into ' || totab || ' values(:r_no, :i_interval, :i_time, :i_index)';
dbms_sql.parse(cursor2, TempSql, dbms_sql.native);
for j in i+TempInter..999 loop
dbms_sql.bind_variable(cursor2, 'r_no', pid);
dbms_sql.bind_variable(cursor2, 'i_interval', pinterval);
dbms_sql.bind_variable(cursor2, 'i_time', TempDate(j));
dbms_sql.bind_variable(cursor2, 'i_index', TempMa(j));
rows_processed := dbms_sql.execute(cursor2);--插入數據
end loop;
end;
end if;
commit;
dbms_sql.close_cursor(cursor2);
--數據量不足跳出
<<JumpLess>>
null;
--exception處理,無關本話題
end;
/
www.2cto.com
(四)個人觀點
在使用dbms_sql系統包的過程中,其方法簡單而又不失靈活,但還是需要注意一些問題:
1、在整個程序的設計過程中,對游標的操作切不可有省略的部分,一旦省略其中某一步驟,則會程序編譯過程既告失敗,如在程序結尾處未對改游標進行關閉操作,則在再次調用過程時會出現錯誤.
2、dbms_sql除了可以做一般的select,insert,update,delete等靜態的sql做能在過程中所做工作外,還能執行create等DDL操作,不過在執行該類操作時應首先顯式賦予執行用戶相應的系統權限,比如create table等.該類操作只需open cursor--->prase--->close cursor即能完成.
以上為本人在工作中對dbms_sql的一點點看法,不到之處,請予指正.
www.2cto.com
附個
Oracle自帶的流程說明(強大啊):
-- The flow of procedure calls will typically look like this:
--
-- -----------
-- | open_cursor |
-- -----------
-- |
-- |
-- v
-- -----
-- ------------>| parse |
-- | -----
-- | |
-- | |---------
-- | v |
-- | -------------- |
-- |-------->| bind_variable | |
-- | ^ ------------- |
-- | | | |
-- | -----------| |
-- | |<--------
-- | v www.2cto.com
-- | query?---------- yes ---------
-- | | |
-- | no |
-- | | |
-- | v v
-- | ------- -------------
-- |----------->| execute | ->| define_column |
-- | ------- | -------------
-- | |------------ | |
-- | | | ----------|
-- | v | v
-- | -------------- | -------
-- | ->| variable_value | | ------>| execute |
-- | | -------------- | | -------
-- | | | | | |
-- | ----------| | | |
-- | | | | v
-- | | | | ----------
-- | |<----------- |----->| fetch_rows |
-- | | | ----------
-- | | | |
-- | | | v
-- | | | --------------------
-- | | | | column_value |
-- | | | | variable_value |
-- | | | ---------------------
-- | | | |
-- | |<--------------------------
-- | |
-- -----------------| www.2cto.com
-- |
-- v
-- ------------
-- | close_cursor |
-- ------------
--
---------------