TYPE IS RECORD 的基本语法为 TYPE 类型名 IS RECORD (字段名 类型 [DEFAULT 值] [NOT NULL]);,支持标量、%TYPE、嵌套记录,作用域限于当前块或包;不可整体比较或判空,赋值为值拷贝;INSERT/UPDATE 中可用但须字段顺序严格匹配。
怎么写 TYPE IS RECORD 的基本语法
直接用 type 关键字加 is record 块就能定义,字段名、类型、默认值、not null 约束都写在括号里,不依赖表结构也能用。
-
TYPE名称自己起,作用域只在当前 PL/SQL 块(比如DECLARE段)或包内,不能跨过程直接复用 - 字段类型支持标量(
VARCHAR2(50))、引用(employees.salary%TYPE)、甚至嵌套记录(另一个RECORD类型) - 可以给字段设默认值:
timeout NUMBER DEFAULT 30,但注意:只有声明变量时才生效,SELECT INTO或赋值后不会回填默认值 - 带
NOT NULL的字段,一旦没初始化或赋值就访问,会报ORA-06502: PL/SQL: numeric or value error
什么时候该用 RECORD 而不是 %ROWTYPE
当你要组合的字段来自多张表、视图、计算列,或者根本没对应物理表时,%ROWTYPE 就不管用了,必须手写 TYPE IS RECORD。
- 比如封装接口入参:一个订单操作要传
order_id、status_code(查码表得来)、processed_at(SYSDATE计算),这三者不在同一张表里 - 又比如做轻量 DTO:把查询结果加工成含描述字段(如
dept_name替代dept_id)的结构,避免后续反复JOIN -
%ROWTYPE是“照抄表结构”,字段增删会导致 RECORD 定义失效;而自定义 RECORD 更稳定,改字段只需同步改一处声明
赋值和比较的常见翻车点
RECORD 支持整体赋值(r2 := r1),但绝不支持整体比较或判空——这是新手最常栽跟头的地方。
- ❌ 错误写法:
IF r1 = r2 THEN ...→ 编译失败,报PLS-00306: wrong number or types of arguments - ✅ 正确做法:逐字段比,
IF r1.id = r2.id AND r1.name = r2.name THEN ... - ❌ 不能写
IF r1 IS NULL THEN→ 语法错误,记录类型没有整体空值语义 - ✅ 判空只能字段级:
IF r1.id IS NULL OR r1.name IS NULL THEN - 注意:整体赋值是值拷贝,修改
r2不会影响r1;但若 RECORD 里有REF CURSOR或对象类型,行为会不同(极少见,一般避开)
能不能在 INSERT / UPDATE 里直接用 RECORD 变量
能,但有严格限制:必须字段顺序、数量、类型完全匹配目标表,且不能含虚拟列或只读列。
- 插入:用
INSERT INTO t VALUES v_rec,前提是v_rec的字段顺序和t的列顺序一致(不是名字匹配) - 更新整行:用
UPDATE t SET ROW = v_rec WHERE ...,同样要求字段顺序对齐;如果只想更新部分字段,还是老实用SET col1 = v_rec.col1, col2 = v_rec.col2 - 别指望用 RECORD 绕过约束:如果表有
NOT NULL列而v_rec对应字段是NULL,DML 一样报错 - 性能上无额外开销,本质还是展开成字段列表,但可读性提升明显——尤其字段多、逻辑分组清晰时
真正麻烦的是嵌套 RECORD 或动态字段数场景,这时候就得换 CREATE TYPE 对象类型,或者干脆用关联数组(TABLE OF RECORD)+ 批量 DML。但日常单行结构封装,TYPE ... IS RECORD 已经够稳、够快、够直白。










