Oracle PL/SQL 动态 SQL 教程:Execute Immediate 和 DBMS_SQL
什么是动态 SQL?
动态 SQL 是一种在运行时生成和执行语句的编程方法。它主要用于编写通用且灵活的程序,在这些程序中,SQL 语句将根据需求在运行时创建和执行。
编写动态 SQL 的方法
PL/SQL 提供了两种编写动态 SQL 的方法
- NDS – 原生动态 SQL
- DBMS_SQL
NDS(原生动态 SQL)– Execute Immediate
原生动态 SQL 是编写动态 SQL 的一种更简单的方法。它使用“EXECUTE IMMEDIATE”命令在运行时创建和执行 SQL。但是,要使用这种方法,运行时使用的变量的数据类型和数量需要提前知道。与 DBMS_SQL 相比,它还提供了更好的性能和更低的复杂性。
语法
EXECUTE IMMEDIATE(<SQL>) [INTO<variable>] [USING <bind_variable_value>]
- 上面的语法显示了 EXECUTE IMMEDIATE 命令。
- INTO 子句是可选的,仅当动态 SQL 包含一个获取值的 SELECT 语句时使用。变量类型应与 SELECT 语句的变量类型匹配。
- USING 子句是可选的,仅当动态 SQL 包含任何绑定变量时使用。
示例 1:在此示例中,我们将使用 NDS 语句从 emp 表中为 emp_no '1001' 获取数据。
DECLARE lv_sql VARCHAR2(500); lv_emp_name VARCHAR2(50): ln_emp_no NUMBER; ln_salary NUMBER; ln_manager NUMBER; BEGIN ly_sql:=;SELECT emp_name,emp_no,salary,manager FROM emp WHERE emp_no=:empmo:; EXECUTE IMMEDIATE lv_sql INTO lv_emp_name,ln_emp_no:ln_salary,ln_manager USING 1001; Dbms_output.put_line('Employee Name:‘||lv_emp_name); Dbms_output.put_line('Employee Number:‘||ln_emp_no); Dbms_output.put_line(‘Salary:'||ln_salaiy); Dbms_output.put_line('Manager ID:‘||ln_manager); END; /
输出
Employee Name : XXX Employee Number: 1001 Salary: 15000 Manager ED: 1000
代码解释
- 代码第 2-6 行:声明变量。
- 代码第 8 行:在运行时构建 SQL。SQL 在 where 条件“:empno”中包含绑定变量。
- 代码第 9 行:使用 NDS 命令“EXECUTE IMMEDIATE”执行已构建的 SQL 文本(在第 8 行完成)。
- “INTO”子句中的变量 (lv_emp_name, ln_emp_no, ln_salary, ln_manager) 用于保存从 SQL 查询 (emp_name, emp_no, salary, manager) 中获取的值。
- “USING”子句为 SQL 查询中的绑定变量(:emp_no)提供值。
- 代码第 10-13 行:显示获取的值。
DBMS_SQL 用于动态 SQL
PL/SQL 提供了 DBMS_SQL 包,允许您使用动态 SQL。创建和执行动态 SQL 的过程包含以下步骤:
- 打开游标:动态 SQL 将以与游标相同的方式执行。因此,为了执行 SQL 语句,我们必须打开游标。
- 解析 SQL:下一步是解析动态 SQL。此过程仅检查语法并将查询准备好执行。
- 绑定变量值:下一步是为绑定变量(如果有)分配值。
- 定义列:下一步是使用 SELECT 语句中相对位置的列来定义它们。
- 执行:下一步是执行已解析的查询。
- 获取值:下一步是获取已执行的值。
- 关闭游标:获取结果后,应关闭游标。
示例 1:在此示例中,我们将使用 DBMS_SQL 语句从 emp 表中为 emp_no '1001' 获取数据。
DECLARE lv_sql VARCHAR2(500); lv_emp_name VARCHAR2(50); ln_emp_no NUMBER; ln_salary NUMBER; ln_manager NUMBER; ln_cursor_id NUMBER; ln_rows_processed; BEGIN lv_sql:=‘SELECT emp_name,emp_no,salary,manager FROM emp WHERE emp_no=:empmo’; in_cursor_id:=DBMS_SQL.OPEN_CURSOR; DBMS_SQL.PARSE(ln_cursor_id,lv_sql,DBMS_SQL.NATIVE); DBMS_SQL.BIXD_VARLABLE(ln_cursor_id,:‘empno‘,1001); DBMS_SQL.DEFINE_COLUMN(ln_cursor_ici,1,ln_emp_name); DBMS_SQL.DEFINE_COLUMN(ln_cursor_id,2,ln_emp_no); DBMS_SQL .DEFINE_COLUMN(ln_cursor_id,3,ln_salary); DBMS_SQL .DEFINE_COLUMN(ln_cursor_id,4,ln_manager); ln_rows__processed:=DBMS_SQL.EXECUTE(ln_cursor_id);
LOOP IF DBMS_SQL.FETCH_ROWS(ln_cursor_id)=0 THEN EXIT; ELSE DBMS_SQL.COLUMN_VALUE(ln_cursor_id,1,lv_emp_name); DBMS_SQL.COLUMN_VALUE(ln_cursor_id,2,ln_emp_no); DBMS_SQL.COLUMN_VALUE(ln_cursor_id,3,In_salary); DBMS_SQL.COLUMN_VALUE(ln_cursor_id,4,In_manager); Dbms_output.put_line('Employee Name:‘||lv_emp_name); Dbms_output.put_line('Employee Number:l‘||ln_emp_no); Dbms_output.put_line(‘Salary:‘||ln_salary); Dbms_output.put_line('Manager ID :‘| ln_manager); END IF; END LOOP; DBMS_SQL.CLOSE_ClIRSOR(ln_cursor_id); END: /
输出
Employee Name:XXX Employee Number:1001 Salary:15000 Manager ID:1000
代码解释
- 代码第 1-9 行:变量声明。
- 代码第 10 行:构建 SQL 语句。
- 代码第 11 行:使用 DBMS_SQL.OPEN_CURSOR 打开游标。它将返回已打开的游标 ID。
- 代码第 12 行:打开游标后,解析 SQL。
- 代码第 13 行:将绑定变量“1001”分配给游标 ID,而不是“:empno”。
- 代码第 14-17 行:根据 SQL 语句中的相对位置定义列名。在我们的例子中,相对位置是 (1) emp_name,(2) emp_no,(3) salary,(4) manager。因此,基于此位置,我们定义了目标变量。
- 代码第 18 行:使用 DBMS_SQL.EXECUTE 执行查询。它返回处理的记录数。
- 代码第 19-33 行:使用循环获取记录并显示。
- 代码第 20 行:DBMS_SQL.FETCH_ROWS 将从已处理的行中获取一条记录。它可以被反复调用以获取所有行。如果它无法获取行,它将返回 0,从而退出循环。
摘要
在本节中,我们讨论了动态 SQL 和执行动态 SQL 的方法。我们还看到了在两种方法中执行动态 SQL 的不同步骤。我们还看到了在两种 NDS 和 DBMS_SQL 方法中处理相同场景以执行运行时操作的示例。