您好!欢迎访问家园网-www.jy.wang!

家园网

Oracle数据库中如何读取游标?RECORD类型变量又是个啥?

网络 作者:本站 点击:

Oracle 游标与 RECORD 类型详解

这是一个非常核心的 Oracle PL/SQL 知识点。让我从基础到实战,彻底讲清楚。


一、Oracle 读取游标的完整流程

在 Oracle 中,读取游标的流程与 SQL Server 类似,但语法不同:

text

┌─────────────────────────────────────────────────────────────┐
│  步骤1:声明游标      →  DECLARE CURSOR                     │
│  步骤2:声明记录变量   →  用于接收每行数据                   │
│  步骤3:打开游标      →  OPEN                               │
│  步骤4:循环取数据     →  LOOP + FETCH + EXIT WHEN          │
│  步骤5:关闭游标      →  CLOSE                              │
└─────────────────────────────────────────────────────────────┘


二、完整代码示例

sql

DECLARE
  -- 1. 声明游标
  CURSOR cur_emp IS
    SELECT empno, ename, sal 
    FROM emp 
    WHERE deptno = 20;
    
  -- 2. 声明 RECORD 类型变量(用来存放一行数据)
  v_emp cur_emp%ROWTYPE;
  BEGIN
  -- 3. 打开游标
  OPEN cur_emp;
  
  -- 4. 循环取数据
  LOOP
    FETCH cur_emp INTO v_emp;
    EXIT WHEN cur_emp%NOTFOUND;  -- 没有数据了就退出
    
    -- 处理每一行数据
    DBMS_OUTPUT.PUT_LINE('员工:' || v_emp.ename || ',工资:' || v_emp.sal);
  END LOOP;
  
  -- 5. 关闭游标
  CLOSE cur_emp;END;/


三、RECORD 类型变量详解

1. 什么是 RECORD?

RECORD(记录类型) 是 Oracle PL/SQL 中的一种复合数据类型,可以包含多个字段,就像一个临时的、只有一行的微型表

2. 为什么需要 RECORD?

问题没有 RECORD有 RECORD
取一行数据需要声明多个变量一个变量就够了
代码长度很长很短
维护性差(列变了要改多处)好(只改一处)

没有 RECORD 的写法(繁琐):

sql

DECLARE
  CURSOR cur_emp IS SELECT empno, ename, sal FROM emp;
  v_empno emp.empno%TYPE;
  v_ename emp.ename%TYPE;
  v_sal emp.sal%TYPE;BEGIN
  OPEN cur_emp;
  LOOP
    FETCH cur_emp INTO v_empno, v_ename, v_sal;  -- 三个变量
    EXIT WHEN cur_emp%NOTFOUND;
    -- 使用 v_empno, v_ename, v_sal
  END LOOP;
  CLOSE cur_emp;END;

有 RECORD 的写法(简洁):

sql

DECLARE
  CURSOR cur_emp IS SELECT empno, ename, sal FROM emp;
  v_emp cur_emp%ROWTYPE;  -- 一个变量搞定所有列BEGIN
  OPEN cur_emp;
  LOOP
    FETCH cur_emp INTO v_emp;  -- 一个变量
    EXIT WHEN cur_emp%NOTFOUND;
    -- 使用 v_emp.empno, v_emp.ename, v_emp.sal
  END LOOP;
  CLOSE cur_emp;END;


四、声明 RECORD 的三种方式

方式1:基于表或游标的 %ROWTYPE(最常用)

sql

-- 基于表v_emp emp%ROWTYPE;  -- 字段和 emp 表完全一样-- 基于游标CURSOR cur_emp IS SELECT empno, ename FROM emp;v_emp cur_emp%ROWTYPE;  -- 字段和游标选中的列一样

方式2:自定义 RECORD 类型

sql

DECLARE
  TYPE emp_record_type IS RECORD (
    empno NUMBER,
    ename VARCHAR2(50),
    sal NUMBER  );
  v_emp emp_record_type;BEGIN
  SELECT empno, ename, sal INTO v_emp FROM emp WHERE rownum = 1;
  DBMS_OUTPUT.PUT_LINE(v_emp.ename);END;

方式3:混合使用

sql

DECLARE
  CURSOR cur_emp IS SELECT empno, ename FROM emp;
  v_emp cur_emp%ROWTYPE;  -- v_emp 只有 empno 和 ename 两个字段BEGIN
  OPEN cur_emp;
  FETCH cur_emp INTO v_emp;
  CLOSE cur_emp;
  DBMS_OUTPUT.PUT_LINE(v_emp.empno || ' - ' || v_emp.ename);END;


五、Oracle 读取游标的三种循环方式

方式1:LOOP...END LOOP(最灵活)

sql

DECLARE
  CURSOR cur_emp IS SELECT empno, ename FROM emp;
  v_emp cur_emp%ROWTYPE;BEGIN
  OPEN cur_emp;
  LOOP
    FETCH cur_emp INTO v_emp;
    EXIT WHEN cur_emp%NOTFOUND;
    -- 处理数据
  END LOOP;
  CLOSE cur_emp;END;

方式2:WHILE 循环

sql

DECLARE
  CURSOR cur_emp IS SELECT empno, ename FROM emp;
  v_emp cur_emp%ROWTYPE;BEGIN
  OPEN cur_emp;
  FETCH cur_emp INTO v_emp;
  WHILE cur_emp%FOUND LOOP
    -- 处理数据
    FETCH cur_emp INTO v_emp;
  END LOOP;
  CLOSE cur_emp;END;

方式3:FOR 循环(最简洁,推荐)

sql

DECLARE
  CURSOR cur_emp IS SELECT empno, ename FROM emp;BEGIN
  FOR v_emp IN cur_emp LOOP
    -- Oracle 自动打开、取数据、关闭游标
    -- v_emp 是隐式声明的 RECORD 变量
    DBMS_OUTPUT.PUT_LINE(v_emp.empno || ' - ' || v_emp.ename);
  END LOOP;END;


六、%ROWTYPE vs %TYPE 对比

属性

%TYPE

%ROWTYPE

作用

取单个列的数据类型

取整行的数据类型

声明

v_name emp.ename%TYPE

v_emp emp%ROWTYPE

存储内容

单个值

整行数据(多个值)

访问方式

直接使用变量名

v_emp.ename(点号访问)


sql

DECLARE
  v_name  emp.ename%TYPE;        -- 只能存一个名字
  v_emp   emp%ROWTYPE;           -- 可以存 empno, ename, sal, hiredate...BEGIN
  SELECT ename INTO v_name FROM emp WHERE rownum = 1;
  SELECT * INTO v_emp FROM emp WHERE rownum = 1;
  DBMS_OUTPUT.PUT_LINE(v_name);           -- 直接使用
  DBMS_OUTPUT.PUT_LINE(v_emp.ename);      -- 点号访问END;/


七、游标属性详解

属性含义返回值
%FOUND最近一次 FETCH 是否取到数据TRUE / FALSE
%NOTFOUND最近一次 FETCH 是否没取到数据TRUE / FALSE
%ROWCOUNT已取出的行数数字
%ISOPEN游标是否已打开TRUE / FALSE

sql

DECLARE
  CURSOR cur_emp IS SELECT ename FROM emp;
  v_ename emp.ename%TYPE;BEGIN
  OPEN cur_emp;
  LOOP
    FETCH cur_emp INTO v_ename;
    EXIT WHEN cur_emp%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE('第 ' || cur_emp%ROWCOUNT || ' 行:' || v_ename);
  END LOOP;
  CLOSE cur_emp;END;/


八、词源角度

单词词源含义
RECORD拉丁语 recordari(记住、回想)记录、档案
ROW古英语 rāw
TYPE拉丁语 typus(模型、类型)类型
CURSOR拉丁语 cursor(奔跑者)游标

%ROWTYPE 的字面意思:"和某表或游标的一行数据同样的类型"


九、总结对比表


对比项

SQL Server

Oracle

接收数据的变量

声明多个 @变量

 %ROWTYPE 一个变量搞定

取数据语法

FETCH INTO @v1, @v2

FETCH INTO v_emp

循环判断

WHILE @@FETCH_STATUS = 0

EXIT WHEN cursor%NOTFOUND

最简方式

没有类似 FOR 循环

FOR v_emp IN cursor LOOP


十、一句话总结

RECORD 类型的变量就像一张只有一行的微型表,可以存储从游标或表中取出的一整行数据。

用 %ROWTYPE 声明 RECORD 变量后,你可以:

  • 用 FETCH cursor INTO v_record 一次性接收整行数据

  • 用 v_record.列名 访问其中的某个字段

  • 代码更简洁、更易维护

Oracle 读取游标最推荐的方式FOR v_emp IN cursor LOOP,它会自动处理开、取、关,你只需要专注处理业务逻辑


标签: