對於通常的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的地方,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所提供定義語句db
mssql.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系統包的過程當中,其方法簡單而又不失靈活,但仍是須要注意一些問題:
一、在整個程序的設計過程當中,對遊標的操做切不可有省略的部分,一旦省略其中某一步驟,則會程序編譯過程既告失敗,如在程序結尾處未對改遊標進行關閉操做,則在再次調用過程時會出現錯誤.
二、dbms_sql除了能夠作通常的select,insert,update,delete等靜態的sql作能在過程當中所作工做外,還能執行create等DDL操做,不過在執行該類操做時應首先顯式賦予執行用戶相應的系統權限,好比create table等.該類操做只需open cursor--->prase--->close cursor即能完成.
以上爲本人在工做中對dbms_sql的一點點見解,不到之處,請予指正.
對於想更深瞭解dbms_sql的朋友,請閱讀dbmssql.sql文件.
www.2cto.com
-- 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 |
-- ------------
--
---------------