EXECUTE IMMEDIATE和Using的用法
一、 EXECUTE IMMEDIATE的作用:
簡單來說 就是你一個儲存過程當中 建立了一個表 table_a 然後要用insert into將其他的資料插入到這個table_a當中,但是因為你在建立過程的時候 table_a還不存在,過程就會顯示有編譯錯誤,因為table_a不存在必然導致過程無法執行,所以無法編譯成功,而把insert into語句加如到 execute immediate之後 則oracle不會再去理會這個物件是否存在,因此可以成功編譯和執行。執行動態SQL語句,舉例str := ‘select * from test’;execute immediate str;多用於拼接的SQL
二、例項
declare
v_sql varchar2(1000);
c varchar2(1000);
a varchar2(1) :='1';
b number :=1;
begin
--當然動態儲存過程可以在這實現了,直接放到v_sql這個變數中就可以了(在這裡是一個指定的過程p_test)
v_sql:='begin p_test(:v1,:v2,:v3); end;';
executeimmediate v_sql using in '1',in '2',out c;
--或executeimmediate v_sql using '1', '2',out c;
dbms_output.put_line(c);
end;
上面我們就實現了動態傳遞引數和動態儲存過程的呼叫方法。值得注意的是:預設為in,in可省,out不可省!
還有一個值得注意的地方就是:每一個動態(executeimmediate)執行的方法都有自己的begin.........end;包住才行呀,如果有多個就這樣寫:
--第一個
begin
v_sql:='begin p_test1(:v1,:v2,:v3); end;';
executeimmediate v_sql using in '1',in '2',out c;
--或executeimmediate v_sql using '1', '2',out c;
dbms_output.put_line(c);
end;
--第二個
begin
v_sql:='begin p_test2(:v1,:v2,:v3); end;';
executeimmediate v_sql using in '1',in '2',out c;
--或executeimmediate v_sql using '1', '2',out c;
dbms_output.put_line(c);
end;
。。。。。。。
--第N個
begin
--
end;
EXECUTEIMMEDIATE代替了以前Oracle8i中DBMS_SQL package包.它解析並馬上執行動態的SQL語句或非執行時建立的PL/SQL塊.動態建立和執行SQL語句效能超前,EXECUTEIMMEDIATE的目標在於減小企業費用並獲得較高的效能,較之以前它相當容易編碼.儘管DBMS_SQL仍然可用,但是推薦使用EXECUTEIMMEDIATE,因為它獲的收益在包之上。
使用技巧
1. EXECUTEIMMEDIATE將不會提交一個DML事務執行,應該顯式提交
如果通過EXECUTEIMMEDIATE處理DML命令,那麼在完成以前需要顯式提交或者作為EXECUTEIMMEDIATE自己的一部分. 如果通過EXECUTEIMMEDIATE處理DDL命令,它提交所有以前改變的資料
2. 不支援返回多行的查詢,這種互動將用臨時表來儲存記錄(參照例子如下)或者用REF cursors.
3. 當執行SQL語句時,不要用分號,當執行PL/SQL塊時,在其尾部用分號.
4. 在Oracle手冊中,未詳細覆蓋這些功能。下面的例子展示了所有用到Executeimmediate的可能方面.希望能給你帶來方便.
5. 對於Forms開發者,當在PL/SQL 8.0.6.3.版本中,Forms 6i不能使用此功能.
EXECUTEIMMEDIATE用法例子
1. 在PL/SQL執行DDL語句
begin
executeimmediate 'set role all';
end;
2. 給動態語句傳值(USING 子句)
declare
l_depnam varchar2(20) := 'testing';
l_loc varchar2(10) := 'Dubai';
begin
executeimmediate 'insert into dept values (:1, :2, :3)'
using 50, l_depnam, l_loc;
commit;
end;
3. 從動態語句檢索值(INTO子句)
declare
l_cnt varchar2(20);
begin
executeimmediate 'select count(1) from emp'
into l_cnt;
dbms_output.put_line(l_cnt);
end;
4. 動態呼叫例程.例程中用到的繫結變數引數必須指定引數型別.黓認為IN型別,其它型別必須顯式指定
declare
l_routin varchar2(100) := 'gen2161.get_rowcnt';
l_tblnam varchar2(20) := 'emp';
l_cnt number;
l_status varchar2(200);
begin
executeimmediate 'begin ' || l_routin || '(:2, :3, :4); end;'
using in l_tblnam, out l_cnt, in out l_status;
if l_status != 'OK' then
dbms_output.put_line('error');
end if;
end;
5. 將返回值傳遞到PL/SQL記錄型別;同樣也可用%rowtype變數
declare
type empdtlrec is record (empno number(4),
ename varchar2(20),
deptno number(2));
empdtl empdtlrec;
begin
executeimmediate 'select empno, ename, deptno ' ||
'from emp where empno = 7934'
into empdtl;
end;
6. 傳遞並檢索值.INTO子句用在USING子句前
declare
l_dept pls_integer := 20;
l_nam varchar2(20);
l_loc varchar2(20);
begin
executeimmediate 'select dname, loc from dept where deptno = :1'
into l_nam, l_loc
using l_dept ;
end;
7. 多行查詢選項.對此選項用insert語句填充臨時表,用臨時表進行進一步的處理,也可以用REF cursors糾正此缺憾.
declare
l_sal pls_integer := 2000;
begin
executeimmediate 'insert into temp(empno, ename) ' ||
' select empno, ename from emp ' ||
' where sal > :1'
using l_sal;
commit;
end;
對於處理動態語句,EXECUTEIMMEDIATE比以前可能用到的更容易並且更高效.當意圖執行動態語句時,適當地處理異常更加重要.應該關注於捕獲所有可能的異常.
三、Using用法簡介
1.靜態SQLSQL與動態SQL
Oracle編譯PL/SQL程式塊分為兩個種:
其一為前期聯編(early binding),即SQL語句在程式編譯期間就已經確定,大多數的編譯情況屬於這種型別;
另外一種是後期聯編(late binding),即SQL語句只有在執行階段才能建立,例如當查詢條件為使用者輸入時,
那麼Oracle的SQL引擎就無法在編譯期對該程式語句進行確定,只能在使用者輸入一定的查詢條件後才能提交給SQL引擎進行處理。
通常,靜態SQL採用前一種編譯方式,而動態SQL採用後一種編譯方式。
本文主要就動態SQL的開發進行討論,並在最後給出一些實際開發的技巧。
2.動態SQL程式開發
理解了動態SQL編譯的原理,也就掌握了其基本的開發思想。
動態SQL既然是一種”不確定”的SQL,那其執行就有其相應的特點。Oracle中提供了Execute immediate語句來執行動態SQL,語法如下:
Excute immediate 動態SQL語句 using 繫結引數列表 returning into 輸出引數列表;
對這一語句作如下說明:
1) 動態SQL是指DDL和不確定的DML(即帶引數的DML)
2) 繫結引數列表為輸入引數列表,即其型別為in型別,在執行時刻與動態SQL語句中的引數(實際上佔位符,可以理解為函式裡面的形式引數)進行繫結。
3) 輸出引數列表為動態SQL語句執行後返回的引數列表。
4) 由於動態SQL是在執行時刻進行確定的,所以相對於靜態而言,其更多的會損失一些系統性能來換取其靈活性。
為了更好的說明其開發的過程,下面列舉一個例項:
設資料庫的emp表,其資料為如下:
ID NAME SALARY
100 Jacky 5600
101 Rose 3000
102 John 4500
要求:
1.建立該表並輸入相應的資料。
2.根據特定ID可以查詢到其姓名和薪水的資訊。
3.根據大於特定的薪水的查詢相應的員工資訊。
根據前面的要求,可以分別建立三個過程(均使用動態SQL)來實現:
過程一:
create or replace procedure create_table as
begin
execute immediate '
create table emp(id number,
name varchar2(10)
salary number; )'; --動態SQL為DDL語句
insert into emp
values (100,'jacky',5600);
insert into emp
values (101,'rose',3000);
insert into emp
values (102,'john',4500);
end create_table;
過程二:
create or replace procedure find_info(p_id number) as
v_name varchar2(10);
v_salary number;
begin
execute immediate '
select name,salary from emp
where id=:1'
using p_id
returning into v_name,v_salary; --動態SQL為查詢語句
dbms_output.put_line(v_name ||'的收入為:'||to_char(v_salary));
exception
when others then
dbms_output.put_line('找不到相應資料');
end find_info;