動態 SQL 在執行階段組裝並執行 SQL 字串,解決靜態 SQL 無法應對的「查詢條件不確定、DDL 執行、物件名稱參數化」等場景。核心機制為晚期綁定,透過 EXECUTE IMMEDIATE 或動態游標實現。
EXECUTE IMMEDIATE dynamic_sql_string
[USING bind_arg_list]
[RETURNING INTO out_arg_list];
USING:綁定輸入參數(對應 SQL 中的 :1, :2...)。RETURNING INTO:接收 DML 的 RETURNING 子句或單行查詢結果。CREATE OR REPLACE PROCEDURE create_table AS
BEGIN
EXECUTE IMMEDIATE '
CREATE TABLE emp(
id NUMBER,
name VARCHAR2(10),
salary NUMBER
)';
-- DDL 隱含提交,無需 COMMIT
END;
CREATE OR REPLACE PROCEDURE find_info(p_id NUMBER) AS
v_name VARCHAR2(10);
v_sal NUMBER;
BEGIN
EXECUTE IMMEDIATE
'SELECT name, salary FROM emp WHERE id = :1'
USING p_id
RETURNING INTO v_name, v_sal;
DBMS_OUTPUT.PUT_LINE(v_name || ' 薪資:' || v_sal);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('查無資料');
END;
CREATE OR REPLACE PROCEDURE find_emp(p_sal NUMBER) AS
TYPE rc IS REF CURSOR;
c rc;
r_emp emp%ROWTYPE;
BEGIN
OPEN c FOR 'SELECT * FROM emp WHERE salary > :1' USING p_sal;
LOOP
FETCH c INTO r_emp;
EXIT WHEN c%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('ID:' || r_emp.id || ' Name:' || r_emp.name);
END LOOP;
CLOSE c;
END;
| 技巧 | 核心 | 程式碼對比 |
|---|---|---|
| 1. SQL 文本重用 | 盡量保持 SQL 字串結構一致,利用 Shared Pool 緩存解析樹 | ❌ 每次拼接字面值 ✅ 統一使用綁定變數 :1 |
| 2. 批量綁定 | FORALL 取代 FOR 迴圈,一次送入陣列 |
❌ FOR i IN 1..n LOOP EXECUTE IMMEDIATE ... USING arr(i); END LOOP;✅ FORALL i IN 1..n EXECUTE IMMEDIATE ... USING arr(i); |
| 3. NOCOPY 參數傳遞 | 大型集合/物件以引用傳遞,避免複製開銷 | PROCEDURE proc(p_coll IN OUT NOCOPY big_collection); |
USING 綁定。EXECUTE IMMEDIATE 內的 SQL 字串不可包含分號(PL/SQL 區塊除外)。動態 SQL 雖以效能換取彈性,善用上述技巧即可將效能損耗壓縮至最低。