1、靜態SQL和動態SQL的概念。sql
一、靜態SQL數據庫
靜態SQL是咱們經常使用的使用SQL語句的方式,就是編寫PL/SQL時,SQL語句已經編寫好了。由於靜態SQL是在編寫程序時就肯定了,咱們只能使用SQL中的DML和事務控制語句,可是DDL語句,以及會話控制語句卻不能再PL/SQL中直接使用,如動態建立表或者某個不肯定的操做時,這就須要動態SQL來實現。緩存
二、動態SQL函數
動態SQL是指在PL/SQL編譯時SQL語句是不肯定的,如根據用戶輸入的參數的不一樣來執行不一樣的操做。編譯程序對動態語句部分不進行處理,只是在程序運行時動態建立語句,對語句進行分析,病執行該語句。性能
靜態SQL的優點是性能較高,但不靈活。動態SQL的優點是靈活,缺點是性能稍差。spa
2、動態建立DML、DDL的SQL語句。code
動態建立SQL有一下幾類:對象
一、DDL語句、DCL語句、非查詢的DML語句、單行查詢的SELECT語句,這類可使用EXECUTE IMMEDIATE語句執行。blog
二、多行查詢的SELECT語句可使用遊標來實現。索引
三、經過DBMS_SQL程序包實現。
下面來介紹以上3種狀況:
一、使用EXECUTE IMMEDIATE語句處理相關語句:
語法:
EXECUTE IMMEDIATE dynamic_sql_string
[into define_variable_list]
[using bind_argument_list];
例:
動態建立表t1
--處理DDL、DCL語句,根據用戶輸入的代表及字段名動態建立表t1 DECLARE tablename VARCHAR2(20); --表名 field1 VARCHAR2(20); --字段1名稱 datatype1 VARCHAR2(20); --字段1類型 field2 VARCHAR2(20); --字段2名稱 datatype2 VARCHAR2(20); --字段2類型 str_sql VARCHAR2(500); --拼接SQL語句的字符串 BEGIN tablename := 't1'; field1:='id'; datatype1:='number'; field2:='name'; datatype2:='varchar(20)'; str_sql := 'create table '||tablename||'('||field1 ||' '||datatype1||','||field2 ||' '||datatype2||')'; EXECUTE IMMEDIATE str_sql; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.put_line('操做失敗!'); END;
動態插入數據;
--動態處理費查詢的DML語句:向剛纔建立的表中插入數據 DECLARE v_id NUMBER; --輸入序號; v_name VARCHAR(20); --輸入姓名; str_sql VARCHAR2(500); --保存拼接的SQL語句 BEGIN v_id := &vid; v_name := '&name'; str_sql := 'insert into t1 values(:1,:2)'; --使用佔位符表明變量 EXECUTE IMMEDIATE str_sql USING v_id,v_name; --使用變量替換SQL中的佔位符,v_id替換:1,v_name替換:2,依此類推。 COMMIT; --執行完畢後直接提交 END;
查詢表中的數據有多少行
--處理單行查詢的SELECT舉例,查詢表中的數據有多少行 DECLARE v_count NUMBER; str_sql VARCHAR2(500); BEGIN str_sql := 'select count(*) from t1'; EXECUTE IMMEDIATE str_sql INTO v_count; --將查詢的結果存放到變量v_count中。 DBMS_OUTPUT.put_line(v_count); END;
綁定變量的優缺點:
1)能夠再庫緩存中共享遊標,節省了CPU等資源,能夠避免額外開銷。
2)SQL語句使用綁定變量能夠避免被注入攻擊。
3)綁定變量是一種減小應用程序在分析查詢時使用栓鎖數目的可靠方法。
不適合使用變量綁定的狀況:
1)對於隔至關長一段時間才執行一次的SQL語句,利用綁定變量的好處hi被不能有效利用而抵消。
2)在數據倉庫的狀況下。
3)在對建有索引的字段,且字段很是大時,利用綁定變量可能會致使查詢計劃錯誤,從而致使查詢效率很是低。
實現DDL語句中的注意事項:
PL/SQL塊使用動態SQL執行DDL語句的時候與其它不一樣,在DDL中不能使用綁定變量。
實現DML語句中的注意事項:
不能使用綁定變量替換實際的數據庫對象名(表,視圖,列等),只能替換字面兩,若是對象名在運行時生成的,咱們只能使用字符串拼接。
二、經過遊標實現多行查詢的SELECT語句
REF遊標能夠處理返回屆國際的動態SQL。實現動態SQL的REF遊標聲明和普通REF遊標相同,知識OPEN時綁定的是動態SQL字符串。
例:查詢emp表中全部的數據。
DECLARE TYPE ref_cur IS REF CURSOR; rc ref_cur; emprow emp%ROWTYPE; v_sql VARCHAR2(100):= 'select * from emp where deptno = :x'; --動態執行的SQL語句 BEGIN OPEN rc FOR v_sql USING 30; --打開遊標,綁定執行的SQL語句,並傳遞參數 LOOP FETCH rc INTO emprow; EXIT WHEN rc%NOTFOUND; dbms_output.put_line('name:'||emprow.ename||' sal:'||emprow.sal); END LOOP; CLOSE rc; END;
三、DBMS_SQL程序包
DBMS_SQL程序包是系統提供給咱們的另外一種使用動態SQL的方法。程序包中封裝了一些列存儲過程,幫助咱們動態執行SQL。
使用DBMS_SQL包實現動態SQL的步驟以下:
1)將要執行的SQL語句或一個語句塊放到一個字符串變量中。
2)使用DBMS_SQL包的parse過程來分析該字符串。
3)使用DBMS_SQL包的bind_variable過程來綁定變量。
4)使用DBMS_SQL包的execute函數來執行語句。
例:使用DBMS_SQL建立表
DECLARE tablename VARCHAR2(20) :='t2'; --表名 field1 VARCHAR2(20) :='id'; --字段1名稱 datatype1 VARCHAR2(20) :='number'; --字段1類型 field2 VARCHAR2(20) :='name'; --字段2名稱 datatype2 VARCHAR2(20) :='varchar(20)'; --字段2類型 v_sql VARCHAR2(500) := 'create table '||tablename||'('||field1 ||' '||datatype1||','||field2 ||' '||datatype2||')'; --拼接SQL語句的字符串 v_cursor NUMBER; --定義光標 v_row NUMBER; --行數 BEGIN v_cursor:=dbms_sql.open_cursor; --爲處理打開光標 dbms_sql.parse(v_cursor,v_sql,dbms_sql.native); --分析語句; v_row:=DBMS_SQL.execute(v_cursor); --執行sql語句; dbms_sql.close_cursor(v_cursor); --關閉光標; DBMS_OUTPUT.put_line(v_row); END;
向表中插入一條數據:
DECLARE v_id NUMBER := &vid; v_name VARCHAR2(20) := '&vname'; v_sql VARCHAR2(100) := 'insert into t2 values(:id,:name)'; v_cursor NUMBER; v_row NUMBER; BEGIN v_cursor:=dbms_sql.open_cursor; dbms_sql.parse(v_cursor,v_sql,dbms_sql.native); dbms_sql.bind_variable(v_cursor,':id',v_id); dbms_sql.bind_variable(v_cursor,':name',v_name); v_row := dbms_sql.execute(v_cursor); dbms_sql.close_cursor(v_cursor); COMMIT; DBMS_OUTPUT.put_line(v_row); END;
查詢EMP中的數據
DECLARE V_DEPTNO NUMBER := &DEPTNO; V_SQL VARCHAR2(100) := 'select empno,ename,sal from emp where deptno = :deptno'; V_CURSOR NUMBER; V_NO NUMBER; V_ENAME VARCHAR2(20); V_SAL NUMBER; v_start NUMBER; BEGIN V_CURSOR := DBMS_SQL.OPEN_CURSOR; --打開遊標 DBMS_SQL.PARSE(V_CURSOR, V_SQL, DBMS_SQL.NATIVE); --解析動態SQL語句 DBMS_SQL.BIND_VARIABLE(V_CURSOR, ':deptno', V_DEPTNO); --傳遞參數 DBMS_SQL.DEFINE_COLUMN(V_CURSOR, 1, V_NO); --定義輸出的列,和查詢的列相匹配 DBMS_SQL.DEFINE_COLUMN(V_CURSOR, 2, V_ENAME,20); DBMS_SQL.DEFINE_COLUMN(V_CURSOR, 3, V_SAL); v_start := DBMS_SQL.execute(V_CURSOR); --執行SQL語句,須要有接受返回值 LOOP EXIT WHEN DBMS_SQL.FETCH_ROWS(V_CURSOR) <= 0; --解析遊標, DBMS_SQL.COLUMN_VALUE(V_CURSOR, 1, V_NO); --將當前行的數據寫入上面對應的列中。 DBMS_SQL.COLUMN_VALUE(V_CURSOR, 2, V_ENAME); DBMS_SQL.COLUMN_VALUE(V_CURSOR, 1, V_SAL); DBMS_OUTPUT.PUT_LINE('no:' || V_NO || ' enmae:' || V_ENAME ||' sal:' || V_SAL); --輸出內容 END LOOP; dbms_sql.close_cursor(v_cursor); --關閉遊標 END;