oracle11g中的游标
- 一、案例引入
- 二、什么是游标
- 三、隐式游标
- 1、隐式游标的属性
- 2、创建语法
- 3、示例
- 四、显示游标
- 1、显示游标的属性
- 2、创建语法
- 3、示例
- 五、REF游标
- 1、REF游标的属性
- 2、创建语法
- 3、示例
- 六、循环游标
- 1、 循环游标的作用
- 2、用for 与 loop 创建
- 3、示例
一、案例引入
假设我们有一个名为employee
的表,其中存储了员工的信息,包括员工ID、姓名、部门和工资等。现在我们需要编写一个PL/SQL存储过程,用于计算每个部门的平均工资,并将结果输出到控制台。在这个业务案例中,我们可以使用游标来实现这个逻辑,因为需要对每个部门进行单独的计算并输出结果。
首先,让我们创建一个名为employee
的示例表,并插入一些数据:
CREATE TABLE employee (employee_id NUMBER,employee_name VARCHAR2(100),department VARCHAR2(100),salary NUMBER
);INSERT INTO employee (employee_id, employee_name, department, salary) VALUES (1, 'Alice', 'HR', 3000);
INSERT INTO employee (employee_id, employee_name, department, salary) VALUES (2, 'Bob', 'HR', 3500);
INSERT INTO employee (employee_id, employee_name, department, salary) VALUES (3, 'Charlie', 'IT', 4000);
INSERT INTO employee (employee_id, employee_name, department, salary) VALUES (4, 'David', 'IT', 3800);
INSERT INTO employee (employee_id, employee_name, department, salary) VALUES (5, 'Eve', 'IT', 4200);
接下来,我们可以编写一个存储过程,使用游标计算每个部门的平均工资,并将结果输出到控制台:
CREATE OR REPLACE PROCEDURE calculate_average_salary IS-- 声明游标CURSOR department_cursor ISSELECT department, AVG(salary) AS avg_salaryFROM employeeGROUP BY department;-- 声明游标变量department_name employee.department%TYPE;avg_salary NUMBER;
BEGIN-- 打开游标OPEN department_cursor;-- 循环处理结果集LOOPFETCH department_cursor INTO department_name, avg_salary;EXIT WHEN department_cursor%NOTFOUND;-- 在这里可以处理每一行数据,例如打印到控制台DBMS_OUTPUT.PUT_LINE('Department: ' || department_name || ', Average Salary: ' || avg_salary);END LOOP;-- 关闭游标CLOSE department_cursor;
END;
/
在上面的示例中,我们首先声明了一个名为department_cursor
的游标,它用于查询每个部门的平均工资。然后在存储过程中打开游标,使用循环逐行从游标中获取数据,并在循环中处理每一行数据,最后关闭游标。当我们调用calculate_average_salary
存储过程时,它会计算每个部门的平均工资,并将结果输出到控制台。
这个示例演示了如何使用游标在Oracle中处理业务逻辑,通过游标,我们可以更灵活地处理查询结果集中的数据,实现更复杂的数据操作逻辑。
二、什么是游标
在Oracle 11g中,游标是一种用于在PL/SQL程序中处理查询结果集的数据结构。它允许程序员在程序中对查询结果集进行逐行处理,可以用来遍历和操作查询结果集中的数据。游标可以分为隐式游标、显式游标、 REF 游标。
-
隐式游标:
- 隐式游标是在PL/SQL块中执行
SELECT
语句时自动创建和管理的,程序员无需显式声明和使用。 - 隐式游标的查询结果集会被自动保存在系统生成的游标中,程序员可以直接在PL/SQL块中对结果集进行处理。
- 通过检查隐式游标的属性可以获得最近执行的DML 语句的信息。
- 隐式游标是在PL/SQL块中执行
-
显式游标则需要程序员显式地声明和使用,通常包括以下步骤:
- 声明游标:使用
DECLARE
语句声明游标,指定查询语句和游标的名称。 - 打开游标:使用
OPEN
语句打开游标,执行查询语句并将结果集保存在游标中。 - 循环处理结果集:使用
FETCH
语句从游标中逐行获取数据,并在循环中处理每一行数据。 - 关闭游标:使用
CLOSE
语句关闭游标,释放游标占用的资源。
- 声明游标:使用
-
REF 游标:REF 游标用于处理运行时才能确定的动态 SQL 查询的结果
通过游标,程序员可以更灵活地处理查询结果集中的数据,实现更复杂的数据操作逻辑。因此,游标在Oracle 11g中广泛应用于PL/SQL程序中对查询结果集进行处理。
三、隐式游标
1、隐式游标的属性
隐式游标是在PL/SQL块中执行SELECT语句时自动创建和管理的,程序员无需显式声明和使用。隐式游标的属性包括以下几个方面:
%ROWCOUNT
:返回最近一次执行的SQL语句所影响的行数。%FOUND
:如果最近一次FETCH语句成功获取了一行数据,则返回TRUE;否则返回FALSE。%NOTFOUND
:如果最近一次FETCH语句未成功获取一行数据,则返回TRUE;否则返回FALSE。%ISOPEN
:如果隐式游标当前处于打开状态,则返回TRUE;否则返回FALSE。
这些属性可以在PL/SQL块中直接使用,用于判断查询结果集的状态和影响行数等信息。例如,可以使用%ROWCOUNT
获取受影响的行数,使用%FOUND
和%NOTFOUND
判断是否成功获取了数据行,使用%ISOPEN
判断游标是否处于打开状态。
2、创建语法
隐式游标的语法非常简单,它可以在PL/SQL的FOR循环语句中使用SELECT语句来隐式创建和使用游标。FOR循环语句的语法如下:
FOR loop_index IN select_statement LOOP-- 在这里处理每一行数据
END LOOP;
其中,loop_index
是循环索引变量,它会在每次循环迭代中自动赋值为查询结果集中的一行数据。select_statement
是SELECT语句,它用于查询数据并返回结果集。
3、示例
下面是一个简单的示例,演示了如何在PL/SQL中使用隐式游标:
CREATE OR REPLACE PROCEDURE calculate_order_total_amount IS
BEGIN-- 使用隐式游标,在FOR循环中迭代处理查询结果FOR order_rec IN (SELECT customer_id, SUM(order_amount) AS total_amount FROM orders GROUP BY customer_id) LOOP-- 在这里可以处理每一行数据,例如打印到控制台DBMS_OUTPUT.PUT_LINE('Customer ID: ' || order_rec.customer_id || ', Total Amount: ' || order_rec.total_amount);END LOOP;
END;
/
在上面的示例中,我们使用了一个隐式游标来处理查询结果集中的数据。在FOR循环中,我们使用了一个SELECT语句来查询所有订单的总金额,并按客户ID分组。在循环中,PL/SQL引擎会自动创建一个隐式游标来执行SELECT语句,并迭代处理查询结果集中的数据。在循环中,我们可以使用order_rec
变量来访问每一行数据的字段值,并对数据进行处理。
需要注意的是,隐式游标只能用于一次性使用的简单查询,如果需要对结果集进行多次迭代或进行复杂的数据操作,建议使用显式游标来实现。
四、显示游标
当使用显式游标时,可以通过游标属性来访问有关游标的信息,包括游标的状态、当前行的数据等。下面是关于显式游标的属性、创建语法和应用场景的详细介绍,包含具体代码示例。
1、显示游标的属性
显式游标具有以下几个常用的属性:
- %FOUND:如果最近的FETCH语句成功获取了一行数据,则为TRUE;否则为FALSE。
- %NOTFOUND:如果最近的FETCH语句未能成功获取一行数据,则为TRUE;否则为FALSE。
- %ROWCOUNT:返回最近的OPEN、FETCH或CLOSE语句所涉及的行数。
- %ISOPEN:如果游标是打开状态,则为TRUE;否则为FALSE。
这些属性可以帮助开发人员在处理游标时了解游标的状态和当前行的数据。
2、创建语法
创建显式游标的语法如下:
DECLARECURSOR cursor_name ISselect_statement;
其中,cursor_name
是游标的名称,select_statement
是 SELECT 语句,用于定义游标要查询的数据集。
3、示例
显式游标适用于以下场景:
- 需要对查询结果集进行多次迭代处理。
- 需要在不同的地方打开和关闭游标,或者在不同的地方获取游标的状态信息。
- 需要在游标的生命周期中手动控制游标的状态。
-
下面是一个具体的代码示例,演示了显式游标的属性、创建语法和应用场景:
CREATE OR REPLACE PROCEDURE process_employee_salary IS-- 声明显式游标CURSOR emp_cursor ISSELECT employee_id, employee_name, salary FROM employees;emp_rec emp_cursor%ROWTYPE; -- 声明一个记录类型的变量,用于存储游标返回的数据BEGIN-- 打开游标OPEN emp_cursor;-- 获取游标的状态信息IF emp_cursor%ISOPEN THENDBMS_OUTPUT.PUT_LINE('Cursor is open');END IF;-- 迭代处理查询结果集LOOPFETCH emp_cursor INTO emp_rec; -- 获取游标返回的数据EXIT WHEN emp_cursor%NOTFOUND; -- 当没有更多数据时退出循环-- 处理数据,例如打印到控制台DBMS_OUTPUT.PUT_LINE('Employee ID: ' || emp_rec.employee_id || ', Name: ' || emp_rec.employee_name || ', Salary: ' || emp_rec.salary);END LOOP;-- 获取行数DBMS_OUTPUT.PUT_LINE('Total rows processed: ' || emp_cursor%ROWCOUNT);-- 关闭游标CLOSE emp_cursor;-- 获取游标的状态信息IF NOT emp_cursor%ISOPEN THENDBMS_OUTPUT.PUT_LINE('Cursor is closed');END IF;END; /
在上面的示例中,我们创建了一个名为
emp_cursor
的显式游标,用于查询员工表中的数据。在过程中,我们打开了游标,使用 FETCH 语句迭代处理查询结果集,获取了游标的状态信息,获取了行数,并在最后关闭了游标。这个示例展示了显式游标的属性、创建语法和应用场景。 -
带参数的显示游标案例
以下是一个带参数的游标示例,其中我们使用参数来过滤查询结果集:-- 创建带参数的游标 DECLARECURSOR student_cursor (grade_param NUMBER) ISSELECT xh, xmFROM studentWHERE grade = grade_param;xh_val student.xh%TYPE;xm_val student.xm%TYPE;grade_val NUMBER := 1; -- 设置参数的默认值 BEGIN-- 打开游标OPEN student_cursor(grade_val);-- 迭代处理查询结果集LOOPFETCH student_cursor INTO xh_val, xm_val;EXIT WHEN student_cursor%NOTFOUND;-- 处理查询结果,例如打印到控制台DBMS_OUTPUT.PUT_LINE('Student ID: ' || xh_val || ', Name: ' || xm_val);END LOOP;-- 关闭游标CLOSE student_cursor; END; /
在上面的示例中,我们创建了一个带参数的游标
student_cursor
,该游标接受一个名为grade_param
的参数,并用于过滤查询结果集。我们在声明游标时指定了参数,并在打开游标时传入参数的值。这样就可以根据参数的值来过滤查询结果集,实现了带参数的游标功能。
五、REF游标
在Oracle数据库中,REF游标是一种特殊类型的游标,用于处理具有引用类型的数据。以下是关于REF游标的属性、创建语法和应用场景的详细介绍,包含具体代码示例。
1、REF游标的属性
REF游标具有以下常用属性:
- %FOUND:如果最近的FETCH语句成功获取了一行数据,则为TRUE;否则为FALSE。
- %NOTFOUND:如果最近的FETCH语句未能成功获取一行数据,则为TRUE;否则为FALSE。
- %ROWCOUNT:返回最近的OPEN、FETCH或CLOSE语句所涉及的行数。
- %ISOPEN:如果游标是打开状态,则为TRUE;否则为FALSE。
这些属性与普通显式游标的属性相似,用于获取游标的状态信息。
2、创建语法
创建REF游标的语法如下:
DECLARECURSOR cursor_name ISSELECT REF(column_name) FROM table_name;
其中,cursor_name
是游标的名称,column_name
是包含引用类型数据的列名,table_name
是包含引用类型数据的表名。
3、示例
REF游标适用于以下场景:
- 处理包含引用类型数据的表,例如使用对象类型或嵌套表类型。
- 需要在游标中返回引用类型数据的引用。
- 需要在游标的生命周期中手动控制游标的状态。
下面是一个具体的代码示例,演示了REF游标的属性、创建语法和应用场景:
CREATE OR REPLACE PROCEDURE process_ref_cursor IS-- 声明REF游标CURSOR ref_cursor ISSELECT REF(e) FROM employees e;emp_ref employees%ROWTYPE; -- 声明一个记录类型的变量,用于存储引用类型数据的引用BEGIN-- 打开游标OPEN ref_cursor;-- 获取游标的状态信息IF ref_cursor%ISOPEN THENDBMS_OUTPUT.PUT_LINE('REF Cursor is open');END IF;-- 迭代处理查询结果集LOOPFETCH ref_cursor INTO emp_ref; -- 获取游标返回的引用数据EXIT WHEN ref_cursor%NOTFOUND; -- 当没有更多数据时退出循环-- 处理引用数据,例如打印到控制台DBMS_OUTPUT.PUT_LINE('Employee Name: ' || emp_ref.last_name);END LOOP;-- 获取行数DBMS_OUTPUT.PUT_LINE('Total rows processed: ' || ref_cursor%ROWCOUNT);-- 关闭游标CLOSE ref_cursor;-- 获取游标的状态信息IF NOT ref_cursor%ISOPEN THENDBMS_OUTPUT.PUT_LINE('REF Cursor is closed');END IF;END;
/
在上面的示例中,我们创建了一个名为 ref_cursor
的REF游标,用于查询包含引用类型数据的员工表。在过程中,我们打开了REF游标,使用 FETCH 语句迭代处理查询结果集,获取了游标的状态信息,获取了行数,并在最后关闭了游标。这个示例展示了REF游标的属性、创建语法和应用场景。
六、循环游标
循环游标是一种在数据库中遍历结果集的方法。它可以用于迭代处理查询结果,对每一行数据执行特定的操作。以下是关于循环游标的详细介绍:
1、 循环游标的作用
循环游标的作用是遍历查询结果集中的数据,并对每一行数据执行特定的操作。这种遍历方式允许开发人员逐行处理结果集,执行复杂的业务逻辑,或者将结果集中的数据进行进一步处理。
- 数据处理:循环游标常用于对查询结果进行逐行处理,例如计算、数据转换等。
- 数据校验:可以使用循环游标来逐行校验查询结果,确保数据的完整性和准确性。
- 数据导出:通过循环游标,可以逐行将查询结果导出到其他数据源或文件中。
2、用for 与 loop 创建
使用循环游标,有两种常见的创建语法,一种是使用 FOR 循环,另一种是使用 LOOP 循环。
-
使用 FOR 循环创建循环游标的语法如下所示:
DECLAREvariable1 datatype;variable2 datatype; BEGINFOR rec IN (SELECT column1, column2, ... FROM table_name WHERE condition) LOOPvariable1 := rec.column1;variable2 := rec.column2;-- 在此处处理查询结果END LOOP; END; /
-
使用 LOOP 循环创建循环游标的语法如下所示:
DECLARECURSOR cursor_name ISSELECT column1, column2, ...FROM table_nameWHERE condition;variable1 datatype;variable2 datatype; BEGINOPEN cursor_name;LOOPFETCH cursor_name INTO variable1, variable2, ...;EXIT WHEN cursor_name%NOTFOUND;-- 在此处处理查询结果END LOOP;CLOSE cursor_name; END; /
3、示例
以下是一个具体的示例代码,演示了使用 FOR 循环和 LOOP 循环创建循环游标,并遍历查询结果集:
-
使用 FOR 循环:
DECLARExh_val student.xh%TYPE;xm_val student.xm%TYPE; BEGINFOR rec IN (SELECT xh, xm FROM student) LOOPxh_val := rec.xh;xm_val := rec.xm;DBMS_OUTPUT.PUT_LINE('Student ID: ' || xh_val || ', Name: ' || xm_val);END LOOP; END; /
这段代码是一个 PL/SQL 块,用于遍历名为
student
的表中的数据,并输出学生的学号和姓名到控制台。具体解释如下:DECLARE
:声明部分,用于声明变量和游标。xh_val student.xh%TYPE;
:声明一个变量xh_val
,其类型与表student
中的xh
字段相同。xm_val student.xm%TYPE;
:声明一个变量xm_val
,其类型与表student
中的xm
字段相同。BEGIN
:开始部分,标志着 PL/SQL 块的开始。FOR rec IN (SELECT xh, xm FROM student) LOOP
:使用 FOR 循环创建一个游标rec
,并执行 SELECT 语句以从表student
中获取学号和姓名。xh_val := rec.xh;
:将当前行的学号赋值给变量xh_val
。xm_val := rec.xm;
:将当前行的姓名赋值给变量xm_val
。DBMS_OUTPUT.PUT_LINE('Student ID: ' || xh_val || ', Name: ' || xm_val);
:输出当前行的学号和姓名到控制台。END LOOP;
:结束 FOR 循环。END;
:PL/SQL 块的结束。
-
使用 LOOP 循环:
DECLARECURSOR student_cursor ISSELECT xh, xmFROM student;xh_val student.xh%TYPE;xm_val student.xm%TYPE; BEGINOPEN student_cursor;LOOPFETCH student_cursor INTO xh_val, xm_val;EXIT WHEN student_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE('Student ID: ' || xh_val || ', Name: ' || xm_val);END LOOP;CLOSE student_cursor; END; /
这段代码是一个 PL/SQL 块,用于遍历名为
student
的表中的数据,并输出学生的学号和姓名到控制台。具体解释如下:DECLARE
:声明部分,用于声明变量和游标。CURSOR student_cursor IS SELECT xh, xm FROM student;
:声明一个名为student_cursor
的游标,用于从表student
中选择学号和姓名。xh_val student.xh%TYPE;
:声明一个变量xh_val
,其类型与表student
中的xh
字段相同。xm_val student.xm%TYPE;
:声明一个变量xm_val
,其类型与表student
中的xm
字段相同。BEGIN
:开始部分,标志着 PL/SQL 块的开始。OPEN student_cursor;
:打开游标student_cursor
。LOOP
:开始一个循环,用于逐行处理查询结果。FETCH student_cursor INTO xh_val, xm_val;
:从游标中获取下一行数据,并将学号和姓名赋值给对应的变量。EXIT WHEN student_cursor%NOTFOUND;
:如果游标中没有更多的数据,则退出循环。DBMS_OUTPUT.PUT_LINE('Student ID: ' || xh_val || ', Name: ' || xm_val);
:输出当前行的学号和姓名到控制台。END LOOP;
:结束循环。CLOSE student_cursor;
:关闭游标student_cursor
。END;
:PL/SQL 块的结束。
在上面的示例中,我们演示了使用 FOR 循环和 LOOP 循环创循环游标,并遍历查询结果集,将学生的学号和姓名逐行输出到控制台。