Oracle PL/SQL Cursor:Implicit、Explicit、For Loop 及示例

PL/SQL 中的 CURSOR 是什么?

Cursor 是指向该上下文区域的指针。Oracle 为处理 SQL 语句创建上下文区域,其中包含有关该语句的所有信息。

PL/SQL 允许程序员通过 Cursor 控制上下文区域。Cursor 保存 SQL 语句返回的行。Cursor 所保存的行集称为活动集。这些 Cursor 也可以命名,以便在代码的其他地方引用它们。

Cursor 分为两种类型。

  • 隐式 Cursor
  • 显式 Cursor

隐式 Cursor

当数据库中发生任何 DML 操作时,都会创建一个隐式 Cursor,该 Cursor 保存受该特定操作影响的行。这些 Cursor 不能命名,因此无法在代码的其他地方控制或引用它们。我们只能通过 Cursor 属性引用最近的 Cursor。

显式 Cursor

程序员可以创建命名的上下文区域来执行其 DML 操作,以获得更好的控制。显式 Cursor 应在 PL/SQL 块的声明部分定义,并为代码中需要使用的“SELECT”语句创建。

以下是使用显式 Cursor 所涉及的步骤。

  • 声明 Cursor 声明 Cursor 仅仅意味着为声明部分中定义的“SELECT”语句创建一个命名的上下文区域。此上下文区域的名称与 Cursor 名称相同。
  • 打开 Cursor 打开 Cursor 会指示 PL/SQL 为此 Cursor 分配内存。它将使 Cursor 准备好获取记录。
  • 从 Cursor 获取数据在此过程中,执行“SELECT”语句,并将获取的行存储在分配的内存中。这些现在称为活动集。从 Cursor 获取数据是逐条记录的活动,这意味着我们可以逐条记录地访问数据。每个 fetch 语句将获取一个活动集并保存该特定记录的信息。此语句与在“INTO”子句中获取记录并将其分配给变量的“SELECT”语句相同,但它不会引发任何异常。
  • 关闭 Cursor 一旦所有记录都已获取,我们就需要关闭 Cursor,以便释放分配给此上下文区域的内存。

语法

DECLARE
CURSOR <cursor_name> IS <SELECT statement^>
<cursor_variable declaration>
BEGIN
OPEN <cursor_name>;
FETCH <cursor_name> INTO <cursor_variable>;
.
.
CLOSE <cursor_name>;
END;
  • 在上面的语法中,声明部分包含 Cursor 的声明以及将存储获取数据信息的 Cursor 变量。
  • Cursor 是为 Cursor 声明中给出的“SELECT”语句创建的。
  • 在执行部分,声明的 Cursor 将被打开、获取并关闭。

Cursor 属性

隐式 Cursor 和显式 Cursor 都有某些可以访问的属性。这些属性提供了有关 Cursor 操作的更多信息。以下是不同的 Cursor 属性及其用法。

Cursor 属性 描述
%FOUND 如果最近一次获取操作成功获取了记录,则返回布尔值“TRUE”,否则返回“FALSE”。
%NOTFOUND 此属性的作用与 %FOUND 相反,如果最近一次获取操作未能获取任何记录,则返回“TRUE”。
%ISOPEN 如果给定的 Cursor 已打开,则返回布尔值“TRUE”,否则返回“FALSE”。
%ROWCOUNT 返回数值。它给出受 DML 活动影响的记录的实际计数。

显式 Cursor 示例:

在此示例中,我们将看到如何声明、打开、获取和关闭显式 Cursor。

我们将使用 Cursor 从 emp 表中投影所有员工的姓名。我们还将使用 Cursor 属性设置循环以从 Cursor 中获取所有记录。

Oracle PL/SQL Cursor

DECLARE
CURSOR guru99_det IS SELECT emp_name FROM emp;
lv_emp_name emp.emp_name%type;

BEGIN
OPEN guru99_det;

LOOP
FETCH guru99_det INTO lv_emp_name;
IF guru99_det%NOTFOUND
THEN
EXIT;
END IF;
Dbms_output.put_line(‘Employee Fetched:‘||lv_emp_name);
END LOOP;
Dbms_output.put_line(‘Total rows fetched is‘||guru99_det%R0WCOUNT);
CLOSE guru99_det;
END:
/

输出

Employee Fetched:BBB
Employee Fetched:XXX
Employee Fetched:YYY 
Total rows fetched is 3

代码解释

  • 第 2 行代码:声明 Cursor guru99_det,用于语句‘SELECT emp_name FROM emp’。
  • 第 3 行代码:声明变量 lv_emp_name。
  • 第 5 行代码:打开 Cursor guru99_det。
  • 第 6 行代码:设置基本循环语句以获取“emp”表中的所有记录。
  • 第 7 行代码:获取 guru99_det 数据并将值分配给 lv_emp_name。
  • 第 9 行代码:使用 Cursor 属性‘%NOTFOUND’来确定 Cursor 中的所有记录是否已获取。如果已获取,则返回“TRUE”并且控制将退出循环,否则控制将继续从 Cursor 中获取数据并打印数据。
  • 第 11 行代码:循环语句的退出条件。
  • 第 12 行代码:打印获取的员工姓名。
  • 第 14 行代码:使用 Cursor 属性‘%ROWCOUNT’来查找在 Cursor 中受影响/获取的总记录数。
  • 第 15 行代码:退出循环后,关闭 Cursor 并释放分配的内存。

FOR 循环 Cursor 语句

可以使用“FOR LOOP”语句来处理 Cursor。可以在 FOR 循环语句中将 Cursor 名称替换为范围限制,这样循环将从 Cursor 的第一条记录到最后一条记录工作。Cursor 变量、Cursor 的打开、获取和关闭将由 FOR 循环隐式完成。

语法

DECLARE
CURSOR <cursor_name> IS <SELECT statement>;
BEGIN
  FOR I IN <cursor_name>
  LOOP
  .
  .
  END LOOP;
END;
  • 在上面的语法中,声明部分包含 Cursor 的声明。
  • Cursor 是为 Cursor 声明中给出的“SELECT”语句创建的。
  • 在执行部分,声明的 Cursor 将在 FOR 循环中设置,循环变量“I”在此情况下将作为 Cursor 变量。

Oracle FOR 循环 Cursor 示例:
在此示例中,我们将使用 Cursor-FOR 循环从 emp 表中投影所有员工姓名。

DECLARE
CURSOR guru99_det IS SELECT emp_name FROM emp; 
BEGIN
FOR lv_emp_name IN guru99_det
LOOP
Dbms_output.put_line(‘Employee Fetched:‘||lv_emp_name.emp_name);
END LOOP;
END;
/

输出

Employee Fetched:BBB 
Employee Fetched:XXX
Employee Fetched:YYY

代码解释

  • 第 2 行代码:声明 Cursor guru99_det,用于语句‘SELECT emp_name FROM emp’。
  • 第 4 行代码:为 Cursor 构建“FOR”循环,循环变量为 lv_emp_name。
  • 第 5 行代码:在循环的每次迭代中打印员工姓名。
  • 第 8 行代码:退出循环

注意:在 Cursor-FOR 循环中,无法使用 Cursor 属性,因为 Cursor 的打开、获取和关闭由 FOR 循环隐式完成。