oracle12C--EXECUTE IMMEDIATE語句(61)

  • 它是做什麼的?
    • 作用:該語句可以方便地在PL/SQL程序中執行DML(insert,upate,delete,單列select),DDL(create,alter,drop),DCLGRANT,REVOKE)語句;
    • 語法:

EXECUTE IMMEDIATE 動態SQL字符串 [[BULK COLLECT] INTO 自定義變量,.....| 記錄類型]
[USING [IN | OUT | IN OUT] 綁定參數,.....]
[[RETURNING | RETURN][BULK COLLECT] INTO 綁定參數,....];

該語句由以下3個主要子句組成:
INTO :保存動態SQL執行結果,如果返回多行記錄,則可以通過BULK COLLECT設置批量保存;
USING:用來爲動態SQL設置佔位符設置內容;
RETURNING | RETURN:兩者使用效果一樣,是取得更新表記錄被影響的數據,通過BULK COLLECT來設置批量綁定

注意:在使用USINGRETURNING語句時都可以設置參數模式(IN,OUT,IN OUT),其中對USING子句主要是使用變量定義的內容,所以默認的模式是IN模式。使用RETURNING子句時不需要設置內容,只需要接收返回內容,所以其模式爲OUT

  • 執行動態SQL
    • 示例1:使用動態SQL創建表和PL/SQL塊

DECLARE

v_sql_statement VARCHAR2(200) ;

v_count NUMBER ; -- 保存查找結果

BEGIN

SELECT COUNT(*) INTO v_count FROM user_tables WHERE table_name='MLDN_TAB' ;

IF v_count = 0 THEN -- 數據表不存在

v_sql_statement := 'CREATE TABLE mldn_tab(

id NUMBER PRIMARY KEY ,

url VARCHAR2(50) NOT NULL)' ; -- 定義動態SQL

EXECUTE IMMEDIATE v_sql_statement ;

ELSE -- 數據表存在

v_sql_statement := 'TRUNCATE TABLE mldn_tab' ;

EXECUTE IMMEDIATE v_sql_statement ;

END IF ;

v_sql_statement := 'BEGIN

FOR x IN 1 .. 10 LOOP

INSERT INTO mldn_tab(id,url) VALUES (x , ''www .mldnjava.cn - '' || x) ;

END LOOP ;

END ;' ;

EXECUTE IMMEDIATE v_sql_statement ;

COMMIT ; -- 提交事務

END ;

/

本程序首先判斷要操作的數據表(mldn_tab)是否存在,如果數據表不存在,則使用動態SQL創建一張mldn_tab的數據表,如果存在,則執行TRUNCATE TABLE命令,將mldn_tab數據表中的數據清楚乾淨,之後繼續利用動態SQL執行一個PL/SQL程序塊,向mldn_tab數據表中增加10條記錄,運行流程圖如下:

  • 設置綁定變量
    • 定義:使用動態SQL時,可以在定義SQL字符串裏採用佔位符的方式設置綁定變量,所設置的綁定變量需要在程序運行時動態地使用USING語句設置佔位符內容,而設置綁定變量的方式採用":佔位符名稱"的方式表示;
    • 示例1:使用綁定變量

DECLARE

v_sql_statement VARCHAR2(200) ;

v_deptno dept.deptno%TYPE := 60 ;

v_dname dept.dname%TYPE := 'MLDN' ;

v_loc dept.loc%TYPE := '北京' ;

BEGIN

v_sql_statement := 'INSERT INTO dept(deptno,dname,loc) VALUES (:dno , :dna , :dl)' ;

EXECUTE IMMEDIATE v_sql_statement USING v_deptno,v_dname,v_loc ;

COMMIT ;

END ;

/

此程序不能直接綁定NULL,需要通過變量設置。以下的設置是錯誤的:

EXECUTE IMMEDIATE v_sql_statement USING v_deptno,v_dname,NULL;
如果希望loc的內容爲NULL,可以將v_loc變量設置爲NULL,其他執行部分不做改變;

  • 示例2:利用集合更新多條記錄

DECLARE

v_sql_statement VARCHAR2(200) ;

TYPE deptno_nested IS TABLE OF dept.deptno%TYPE NOT NULL ;

TYPE dname_nested IS TABLE OF dept.dname%TYPE NOT NULL ;

v_deptno deptno_nested := deptno_nested(10,20,30,40) ;

v_dname dname_nested := dname_nested('財務部','研發部','銷售部','操作部') ;

BEGIN

v_sql_statement := 'UPDATE dept SET dname=:dna WHERE deptno=:dno' ;

FOR x IN 1 .. v_deptno.COUNT LOOP

EXECUTE IMMEDIATE v_sql_statement USING v_dname(x),v_deptno(x) ;

END LOOP ;

COMMIT ;

END ;

/

本程序定義了兩個嵌套表類型(deptno_nested,dname_nested),然後將要更新的部門編號及部門名稱分別保存在這兩個嵌套表中,最後採用循環的方式利用
EXECUTE IMMEDIATE動態地執行更新操作

  • 示例3:查詢數據

DECLARE

v_sql_statement VARCHAR2(200) ;

v_empno emp.empno%TYPE := 7369 ;

v_emprow emp%ROWTYPE ;

BEGIN

v_sql_statement := 'SELECT * FROM emp WHERE empno=:eno' ;

EXECUTE IMMEDIATE v_sql_statement INTO v_emprow USING v_empno ;

DBMS_OUTPUT.put_line('僱員編號:' || v_emprow.empno || ',姓名:' || v_emprow.ename || ',職位:' || v_emprow.job) ;

END ;

/

本程序在查詢語句中使用了綁定變量,由於此時需要返回結果,所以通過EXECUTE IMMEDIATE中的INTO子句將查詢結果保存在v_emprow變量中,同時還需要使用USING設置佔位符數據

  • 示例4:上面的示例中,綁定變量的代碼都只是針對基本的數據類型,例如字符串,數字等。這種方式無法針對DDL操作;
    • 在創建表時使用綁定變量

DECLARE

v_sql_statement VARCHAR2(200) ;

v_table_name VARCHAR2(200) := 'mldn' ;

v_id_column VARCHAR2(200) := 'id' ;

BEGIN

v_sql_statement := 'CREATE TABLE :tn (:ci NUMBER PRIMARY KEY)' ;

EXECUTE IMMEDIATE v_sql_statement USING v_table_name,v_id_column ;

END ;

/

運行結果:

錯誤報告:

ORA-00903: 表名無效

ORA-06512: 在 line 7

  • 此時CREATEDDL操作命令,無法使用綁定變量設置表名稱,同理,對於刪除表,截斷表操作也一樣無法使用,如果要使用,可以採用拼接字符串的方式完成,例如:
    • 正確的代碼

DECLARE

v_sql_statement VARCHAR2(200) ;

v_table_name VARCHAR2(200) := 'mldn' ;

v_id_column VARCHAR2(200) := 'id' ;

BEGIN

v_sql_statement := 'CREATE TABLE ' || v_table_name ||' (' || v_id_column ||' NUMBER PRIMARY KEY)' ;

EXECUTE IMMEDIATE v_sql_statement ;

END ;

/

  • 接收DML更新行數
    • 當用戶使用DML更新操作後,可以利用RETURNING INTO子句接收更新後被影響的數據行的詳細信息;
    • 示例1:更新數據,取得更新後的結果

DECLARE

v_sql_statement VARCHAR2(200) ; -- 定義SQL操作語句

v_empno emp.empno%TYPE := 7369 ; -- 要更新的僱員編號

v_salary emp.sal%TYPE ; -- 保存更新後的sal內容

v_job emp.job%TYPE ; -- 保存更新後的job內容

BEGIN

v_sql_statement := 'UPDATE emp SET sal=sal*1.2,job=''開發'' ' ||

' WHERE empno=:eno RETURNING sal,job INTO :salary,:job' ;

EXECUTE IMMEDIATE v_sql_statement USING v_empno RETURNING INTO v_salary,v_job ;

DBMS_OUTPUT.put_line('調整後的工資:' || v_salary || ',新的職位:' || v_job) ;

END ;

/

提示:也可以使用RETURN接收影響數據行的數據,代碼片段如下:

v_sql_statement := 'UPDATE emp SET sal=sal*1.2,job=''開發'' ' ||

' WHERE empno=:eno RETURN sal,job INTO :salary,:job' ;

EXECUTE IMMEDIATE v_sql_statement USING v_empno RETURN INTO v_salary,v_job ;

  • 示例2:刪除數據,取得刪除前的結果

 

DECLARE

v_sql_statement VARCHAR2(200) ; -- 定義SQL操作語句

v_emprow emp%ROWTYPE ; -- 保存emp類型

v_empno emp.empno%TYPE := 7369 ; -- 刪除的僱員編號

v_ename emp.ename%TYPE ; -- 刪除的僱員姓名

v_sal emp.sal%TYPE ; -- 刪除的僱員工資

BEGIN

v_sql_statement := 'DELETE FROM emp WHERE empno=:eno RETURNING ename,sal INTO :name,:sal' ;

EXECUTE IMMEDIATE v_sql_statement USING v_empno RETURNING INTO v_ename,v_sal ;

DBMS_OUTPUT.put_line('刪除的僱員編號:' || v_empno || ',姓名:' || v_ename || ',工資:' || v_sal) ;

END ;

/

運行結果:
刪除的僱員編號:7369,姓名:,工資:

分析:在進行數據刪除時,SQL語句使用RETURNING INTO將要刪除僱員的姓名及職位賦值給兩個綁定變量(:name,:sal),然後在使用EXECUTE IMMEDIATE時通過RETURNING INTO將已刪除僱員的姓名及工資賦值給v_enamev_sal這兩個變量

  • 示例3:編寫部門增加過程

CREATE OR REPLACE PROCEDURE dept_insert_proc(

p_deptno IN OUT dept.deptno%TYPE , -- 此處可以將p_deptno的內容回傳

p_dname dept.dname%TYPE, -- 默認爲IN模式

p_loc dept.loc%TYPE) AS -- 默認爲IN模式

BEGIN

SELECT MAX(deptno) INTO p_deptno FROM dept ; -- 取得最大的deptno內容

p_deptno := p_deptno + 1 ; -- 讓最大值部門編號加1,此處不考慮超過2位數字情況

INSERT INTO dept(deptno,dname,loc) VALUES (p_deptno,p_dname,p_loc) ;

END ;

/

本過程要傳遞3個參數,其中對於部門編號(p_deptno)採用了IN OUT模式,所以此值可以傳回到調用處,在過程裏首先將查詢最大的部門編號。之後依次部門編號爲基礎進行加1的增長,這樣就可以產生一個新的部門編號,並將此部門編號保存在dept表中

  • 接上例:編寫PL/SQL塊,調用過程

DECLARE

v_sql_statement VARCHAR2(200) ;

v_deptno dept.deptno%TYPE ;

v_dname dept.dname%TYPE := 'MLDN' ;

v_loc dept.loc%TYPE := '北京' ;

BEGIN

v_sql_statement := 'BEGIN

dept_insert_proc(:dno , :dna , :dl) ;

END ;' ; -- 定義PL/SQL

EXECUTE IMMEDIATE v_sql_statement USING IN OUT v_deptno , IN v_dname , v_loc ;

DBMS_OUTPUT.put_line('新增部門編號爲:' || v_deptno) ;

END ;

/

此操作使用USING傳遞被綁定的參數,由於在dept_insert_proc()過程中的第一個參數採用了IN OUT模式,所以可以接收部門增加後的部門編號數據

發佈了201 篇原創文章 · 獲贊 62 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章