一:靜態SQL與動態SQL
Oracle編譯PL/SQL程序塊分為兩種:一種為前期聯編(early binding),即SQL語句在程序編譯期間就已經確定,大多數的編譯情況屬於這種類型;另外一種是后期聯編(late binding),即SQL語句只有在運行階段才能建立,例如當查詢條件為用戶輸入時,那么Oracle的SQL引擎就無法在編譯期對該程序語句進行確定,只能在用戶輸入一定的查詢條件后才能提交給SQL引擎進行處理。通常,靜態SQL采用第一種編譯方式,而動態SQL采用后一種編譯方式。
本文主要討論動態SQL的相關內容。
二:動態SQL程序開發
理解了動態SQL編譯的原理,也就掌握了其基本的開發思想。動態SQL既然是一種”不確定”的SQL,那其執行就有其相應的特點。Oracle中提供了Execute immediate語句來執行動態SQL,語法如下:
1 execute immediate 動態SQL語句 2 using 綁定參數列表
1)動態SQL是指DDL和不確定的DML(即帶參數的DML);
2)綁定參數列表為輸入參數列表,即其類型為in類型,在運行時刻與動態SQL語句中的參數(實際上占位符,可以理解為函數里面的形式參數)進行綁定;
3)由於動態SQL是在運行時刻進行確定的,所以相對於靜態而言,其更多的會損失一些系統性能來換取其靈活性。
舉例:設數據庫的emp表,其數據為如下:
ID | NAME | SALARY |
100 | Jacky | 5600 |
101 | Rose | 3000 |
102 | John | 4500 |
1.創建該表、添加數據。
1 declare 2 tablename varchar2(20); --表名 3 field1 varchar2(20); --字段1名稱 4 datatype1 varchar2(20); --字段1類型 5 field2 varchar2(20); --字段2名稱 6 datatype2 varchar2(20); --字段2類型 7 field3 varchar2(20); --字段3名稱 8 datatype3 varchar2(20); --字段3類型 9 str_sql varchar2(500); --拼接sql語句的字符串 10 begin 11 tablename := 'emp'; 12 field1 := 'id'; 13 datatype1 := 'number'; 14 field2 := 'name'; 15 datatype2 := 'varchar(10)'; 16 field3 := 'salary'; 17 datatype3 := 'number'; 18 str_sql := 'create table '||tablename||'('||field1||' '||datatype1||','||field2||' '||datatype2||','||field3||' '||datatype3|| ')'; 19 execute immediate str_sql; 20 exception 21 when others then 22 dbms_output.put_line('操作失敗!'); 23 end;
1 declare 2 v_id number; 3 v_name varchar(20); 4 v_salary number; 5 str_sql varchar2(500); --保存拼接的sql語句 6 begin 7 v_id := &vid; 8 v_name := '&name'; 9 v_salary:= &vsal; 10 11 str_sql := 'insert into emp values(:1,:2,:3)'; --使用占位符代表變量 12 execute immediate str_sql 13 using v_id, v_name,v_salary; --使用變量替換sql中的占位符,v_id替換:1,v_name替換:2,依此類推。 14 15 commit; 16 end;
2.根據大於特定的薪水的查詢相應的員工信息。
1 create or replace procedure find_emp(p_salary number) is 2 v_emp emp%rowtype; 3 type my_cursor is ref cursor; 4 v_my_cursor my_cursor; 5 begin 6 open v_my_cursor for 'select * from emp where salary >:1' 7 using p_salary; 8 9 loop 10 fetch v_my_cursor into v_emp; 11 exit when v_my_cursor%notfound; 12 dbms_output.put_line('薪水大於'||p_salary||' 的員工有: '); 13 dbms_output.put_line('id為 '||v_emp.id||' 姓名為:'||v_emp.name); 14 end loop; 15 close v_my_cursor; 16 end;
3.刪除指定表的數據,並通過out類型參數返回影響的行數。
1 create or replace procedure del_rows(p_table_name in varchar2, 2 p_rows_deld out number) is 3 begin 4 execute immediate 'delete from '||p_table_name; 5 p_rows_deld := sql%rowcount; 6 end;
注意:第2個程序動態SQL語句使用了占位符“:1“,其實它相當於函數的形式參數,使用”:“作為前綴,然后使用using語句將p_salary在運行時刻將:1給替換掉,這里p_salary相當於函數里的實參。其中打開的游標為動態游標,它也屬於動態SQL的范疇,其整個編譯和開發的過程與execute immediate執行的過程很類似。
三:小結
本文對動態SQL的編譯原理、開發過程進行簡單介紹,對動態SQL程序開發有了一個總體的認識。