41.3. 声明

41.3.1. 声明函数参数
41.3.2. 复制类型
41.3.3. 行类型
41.3.4. 记录类型
41.3.5. 异常类型

在块中使用的所有变量都必须在块的声明部分中声明。(唯一的例外是,迭代整数值范围的 FOR 循环的循环变量自动声明为整数变量,类似地,迭代游标结果的 FOR 循环的循环变量自动声明为记录变量。)

pl/sql 变量可以具有任何 SQL 数据类型,例如 integervarcharchar

这里是一些变量声明的示例:

user_id integer;
quantity numeric(5);
url varchar(64);
myrow tablename%ROWTYPE;
myfield tablename.columnname%TYPE;
arow RECORD;

变量声明的一般语法如下:

name [ CONSTANT ] type [ NOT NULL ] { DEFAULT | := } expression;

如果给定了 DEFAULT 子句,则指定在输入块时分配给变量的初始值。 如果未给出 DEFAULT 子句,则会将变量初始化为 SQL 空值。 CONSTANT 选项防止在初始化后对变量进行分配,因此其值将在块的持续时间内保持不变。 如果指定了 NOT NULL,则将空值分配给它会导致运行时错误。 所有声明为 NOT NULL 的变量都必须指定一个非空默认值。

示例:

quantity integer DEFAULT 32;
url varchar(64) := 'http://mysite.com';
user_id CONSTANT integer := 10;

41.3.1. 声明函数参数

声明的函数参数名的数据类型可以是 SQL 参数类型或 pl/sql 参数类型。并且您可以使用 in、 out 和 inout来修改参数。例如:

CREATE FUNCTION sales_tax(subtotal in real) RETURN real IS
BEGIN
    RETURN subtotal * 0.06;
END;
/

如果匿名块需要函数返回值时,使用inout修饰参数,return返回值必须要有具体的返回值,不然返回的就是一个record。例如:

create table nested_tab(id int, name varchar2(100), job varchar2(100), age int);
insert into nested_tab values (2, 'sdfsd', 'cvxvx', 14);

create or replace function nested_func(id1 inout int, name1 inout varchar2(100), job1 inout varchar2(100), age1 inout int)
return int as
  id2 int;
  name2 varchar2(100);
  job2  varchar2(100);
  age2  int;
begin
  select * into id2, name2, job1, age1 from nested_tab where age = 14;
  id1 := id2;
  name1 := name2;
  job1 := job2;
  age1 := age2;
  begin
	id1 := 45;
    name1 := 'name';
    job1 := 'job';
    age1 := 45;
  end;
  return 0;
end;
/

create or replace function nested_func12(id1 inout int, name1 inout varchar2(100), job1 inout varchar2(100), age1 inout int)
return int as
  retcode int;
begin
  begin
	retcode := nested_func(id1, name1, job1, age1);
  end;
  return 1;
end;
/
declare
  id2 int;
  name2 varchar2(100);
  job2  varchar2(100);
  age2  int;
  retcode int;
begin
   begin
	retcode := nested_func12(id2, name2, job2, age2);
  end;
  dbms_output.put_line(id2 || name2 || job2 || age2);
end;
/

41.3.2. 复制类型

variable%TYPE

%TYPE 提供变量或表列的数据类型。您可以使用它来声明将保存数据库值的变量。例如,假设在您的 users 表中有一个名为 user_id 的列。要声明一个与 users.user_id 具有相同数据类型的变量,您可以编写:

user_id users.user_id%TYPE;

通过使用 %TYPE,您不需要知道所引用的结构的数据类型,最重要的是,如果所引用的项目的数据类型在将来发生更改(例如:将 user_id 的类型从 integer 更改为 real),您可能不需要更改函数定义。

在多态函数中,%TYPE 特别有价值,因为内部变量所需的数据类型可能会从一次调用到下一次调用发生变化。可以通过将 %TYPE 应用于函数的参数或结果占位符来创建适当的变量。

%TYPE 也可以用来声明包类型变量。要声明一个数据类型与 package.variable 相同的变量,您可以这样写:

var package.variable%TYPE;

41.3.3. 行类型

name table_name%ROWTYPE;

复合类型的变量称为 变量(或 行类型 变量)。这样的变量可以保存 SELECTFOR 查询结果的整行,只要该查询的列集与变量的声明类型匹配即可。 访问行值的各个字段使用通常的点标记法,例如 rowvar.field

可以使用 table_name%ROWTYPE 符号将行变量声明为具有与现有表或视图的行相同类型的变量;或者可以通过给出复合类型的名称来声明它。 (由于每个表都有与其名称相同的关联复合类型,因此实际上在 LightDB 中无论您是否编写 %ROWTYPE 都无关紧要。但是带有 %ROWTYPE 的形式更具可移植性。)

41.3.4. 记录类型

name RECORD;

记录变量类似于行类型变量,但它们没有预定义的结构。它们在 SELECTFOR 命令期间分配的行上采用实际的行结构。记录变量的子结构可能每次分配给它时都会发生变化。 这样的结果是,直到首次分配给记录变量之前,它没有子结构,任何尝试访问其中的字段都会引发运行时错误。

请注意,RECORD 不是真正的数据类型,只是一个占位符。还应该意识到,当声明一个返回类型为 record 的函数时,这与记录变量的概念并不完全相同,尽管这样的函数可能使用记录变量来保存其结果。在两种情况下,当编写函数时,实际的行结构是未知的,但对于返回 record 的函数,在解析调用查询时确定实际结构,而记录变量可以在运行时更改其行结构。

41.3.5. 异常类型

name EXCEPTION;

异常类型用来申明用户自定义异常变量,在申明变量之后使用PRAGMA EXCEPTION_INIT(exception_variable, error_code)命令来初始化异常代码。

请注意,EXCEPTION 变量的取值范围在除-1403外的大于-100000的负数和正数100。