知識點的梳理:
- 使用動態SQL可以在依賴對象不存在時創建子程序;
- 動態SQL主要利用EXECUTE IMMEDIATE 語句執行DML,DDL,DCL等語句操作;
- 如果使用了綁定變量,則必須在EXECUTE IMMEDIATE中使用USING子句設置所需要的綁定變量;
- 使用RETURNING或RETURN語句可以接收查詢或更新後的返回結果;
-
使用批處理可以一次性將數據庫中取回的多個數據保存在集合中,或者使用FORALL將多個綁定參數設置到動態SQL中;
-
動態SQL簡介
- PL/SQL程序有一個特點:所操作的數據庫對象必須存在,否則創建的子程序會出現問題,這種操作被稱爲靜態SQL操作;
-
動態SQL可讓用戶在定義程序時不指定具體的操作對象,在執行時動態傳入需要的數據庫對象,讓程序更加靈活;
- 相對與靜態SQL,動態SQL在程序編譯時無法檢測數據對象是否存在,是否有指定的操作權限,只能等運行時才能發現這些錯誤;
-
Oracle構建動態SQL,可以使用NDS或DBMS_SQL包兩種方式完成。在Oracle11g中,動態SQL的構建主要依靠NDS方式來完成,因爲NDS方式完成的動態SQL運行速度比DBMS_SQL包快,同時在NDS中也使用了比DBMS_SQL包中更簡單的語法:
- NDS主要使用的是EXECUTE IMMEDIATE語句;
- 處理多行數據,可用遊標,以及批量SQL;
-
舉個栗子
- 示例1:利用動態SQL在執行時創建一張數據表
CREATE OR REPLACE FUNCTION get_table_count_fun(p_table_name VARCHAR2) RETURN NUMBER AS v_sql_statement VARCHAR2(200) ; -- 定義操作的SQL語句 v_count NUMBER ; -- 保存表中記錄 BEGIN SELECT COUNT(*) INTO v_count FROM user_tables WHERE table_name=UPPER(p_table_name) ; IF v_count = 0 THEN -- 數據表不存在 v_sql_statement := 'CREATE TABLE ' || p_table_name || ' ( id NUMBER , name VARCHAR2(30) NOT NULL , CONSTRAINT pk_id_' || p_table_name || ' PRIMARY KEY(id)) ' ; -- 創建數據表 EXECUTE IMMEDIATE v_sql_statement ; -- 執行動態SQL END IF ; v_sql_statement := 'SELECT COUNT(*) FROM ' || p_table_name ; -- 查詢數據表記錄 EXECUTE IMMEDIATE v_sql_statement INTO v_count ; -- 執行動態SQL並保存數據記錄 RETURN v_count ; END ; / |
流程圖: |
- 接上例:編寫PL/SQL塊調用函數
BEGIN DBMS_OUTPUT.put_line('數據表記錄:' || get_table_count_fun('mldnjava')) ; END ; / |
本程序會直接輸出get_table_count_fun()函數的返回結果,在函數操作中,如果要操作的數據表不存在則會自動創建,本程序中輸入的mldnjava數據表不存在,執行後可以發現此表自動創建; |
問題:在執行get_table_count_fun()函數時,可能會出現"ORA-01031:權限不足"錯誤: CONN sys/change_on_install AS SYSDBA ; GRANT CREATE ANY TABLE TO c##scott ; CONN c##scott/tiger ; 授權之後,重新使用scott登錄,就可以正常使用get_table_count_fun()了 |
-
一些問題
-
提示1:如果不使用EXECUTE IMMEDIATE,程序會出現錯誤
- 下面的程序由於要操作的數據庫對象可能不存在,如果用戶直接使用DDL或DML操作就會出現編譯錯誤;
- 示例:直接在程序中編寫DDL或DML
-
CREATE OR REPLACE FUNCTION get_table_count_fun(p_table_name VARCHAR2) RETURN NUMBER AS v_sql_statement VARCHAR2(200) ; -- 定義操作的SQL語句 v_count NUMBER ; -- 保存表中記錄 BEGIN SELECT COUNT(*) INTO v_count FROM user_tables WHERE table_name=UPPER(p_table_name) ; IF v_count = 0 THEN -- 數據表不存在 -- 錯誤:無法直接使用DDL操作 CREATE TABLE p_table_name ( id NUMBER , name VARCHAR2(30) NOT NULL , CONSTRAINT id_pk PRIMARY KEY(id)) ; END IF ; -- 錯誤:查詢數據表不存在 SELECT COUNT(*) INTO v_count FROM p_table_name ; RETURN v_count ; END ; / |
此時發現,在創建數據表的執行語句上出現了錯誤,這是因爲PL/SQL早期綁定特性,所以導致無法執行DDL |