PL/SQL变量声明必须显式指定类型,不支持无类型声明;基础类型需带长度或精度,%TYPE用于表字段类型引用,%ROWTYPE适用于整行操作但需注意内存与顺序,所有变量默认为NULL,须显式初始化。
PL/SQL里变量声明必须带类型,不能像JavaScript那样DECLARE x;
pl/sql是强类型语言,所有变量在declare块中必须显式指定类型,否则编译直接报错pls-00215: string length constraints must be in range (1 .. 32767)这类类型缺失错误。常见误写是漏掉类型或只写变量名不跟type——这在sql*plus或sql developer里会立刻失败。
实操建议:
- 基础类型必须用标准写法:
emp_name VARCHAR2(100)、salary NUMBER(8,2)、is_active CHAR(1) -
VARCHAR2长度必须指定,写VARCHAR2不带括号会报错;CHAR同理,不写长度默认为1,容易引发截断隐含问题 - 数值类型别乱套用
NUMBER:如果只存整数,用PLS_INTEGER更快;如果涉及高精度计算(如财务),才用NUMBER(p,s) - 日期一律用
DATE,别用字符串模拟——否则TO_DATE转换出错、时区混乱、索引失效全跟着来
用%TYPE引用表字段类型,但别在游标变量上硬套
%TYPE本质是编译期类型别名,它让变量和某个列“长得一样”,好处是表结构改了,PL/SQL不用同步改声明。但它不是万能的:比如你写emp_sal employees.salary%TYPE,那emp_sal就完全继承employees.salary的类型定义(包括精度、是否可为NULL)。
实操建议:
- 只对数据库表/视图字段用
%TYPE,例如v_name employees.last_name%TYPE - 别对游标字段用
%TYPE,像c1_rec emp_cursor%ROWTYPE才是正解;若强行写c1_name emp_cursor.name%TYPE,Oracle会报PLS-00329: reference to cursor 'EMP_CURSOR' must be made through a variable -
%TYPE无法跨Schema自动解析权限,如果引用的是其他用户表(如hr.employees.salary%TYPE),当前用户得有SELECT权限,否则编译失败 - 函数返回值类型不能用
%TYPE,比如res some_func() %TYPE语法非法,得先查函数定义再手动写类型
%ROWTYPE适合整行操作,但注意内存开销和字段顺序依赖
%ROWTYPE声明的是记录类型,对应一张表或游标的一整行。它方便赋值(SELECT ... INTO rec)、传参、甚至做简单比较,但背后是按字段顺序逐个拷贝,不是指针引用。
实操建议:
- 表字段多、行宽大时慎用:比如一张50列、含
CLOB的表,rec my_table%ROWTYPE会在PGA里分配大量内存,可能触发ORA-04030: out of process memory - 赋值必须严格匹配字段顺序:
SELECT col_a, col_b INTO rec FROM t要求t的查询列顺序和rec定义顺序一致,否则报PLS-00394: wrong number of values in the INTO list - 不能直接给
%ROWTYPE变量赋NULL,得用rec := NULL(语法允许)或逐字段清空,否则后续IS NULL判断行为不可靠 - 如果只是读几个字段,别贪图省事全用
%ROWTYPE,拆成独立变量更轻量、更可控
复合类型变量初始化要动手,PL/SQL不会自动设默认值
PL/SQL里任何变量声明后都是NULL,包括NUMBER、DATE、VARCHAR2,哪怕你写了cnt NUMBER := 0这种带初值的,也只是语句级行为,不是类型层面的默认值。这点和Java的成员变量初始化完全不同。
实操建议:
- 所有需要非NULL初始值的变量,必须显式赋值:
status VARCHAR2(10) := 'PENDING',否则后续NVL(status, 'UNKNOWN')可能掩盖逻辑缺陷 -
%TYPE和%ROWTYPE变量也一样:声明v_emp employees%ROWTYPE后,v_emp.employee_id仍是NULL,不能假设它等于0或空字符串 - 布尔型变量(
BOOLEAN)尤其危险:未初始化的flag BOOLEAN在IF flag THEN ...里会进ELSE分支,但IF NOT flag也会进ELSE——因为NULL既不真也不假 - 过程参数如果是
IN OUT,调用前也得确保传入变量已初始化,否则子程序内部:=赋值可能被忽略
%TYPE看着省事,结果表结构一变、权限一调、字段一加,整个包就编译不过——这时候翻错误信息比猜逻辑快得多。

















