1. 程式人生 > >EXECUTE IMMEDIATE和Using的用法

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

二、例項

    有一個儲存過程名為:p_test,它有三個引數,分別為:兩個輸入引數和一個輸出引數,實現過程如:
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;