PostgreSQL 8.0.0 中文文档(PostgreSQL 中国制作) | ||||
---|---|---|---|---|
Prev | Fast Backward | Chapter 35. PL/pgSQL - SQL 过程语言 | Fast Forward | Next |
所有在块里使用的变量都必须在一个块的声明段里声明。 (唯一的例外是一个FOR循环里的循环变量是在一个整数范围内迭代的,被自动声明为整数变量。)
PL/pgSQL变量可以用任意的 SQL 数据类型,比如 integer,varchar 和 char。
下面是一些变量声明的例子∶
user_id integer; quantity numeric(5); url varchar; myrow tablename%ROWTYPE; myfield tablename.fieldname%TYPE; arow RECORD;
一个变量声明的一般性语法是∶
name [ CONSTANT ] type [ NOT NULL ] [ { DEFAULT | := } expression ];
如果给出了DEFAULT子句,那么它声明了在进入该块的时候赋予该变量的初始值。 如果没有给出DEFAULT子句,那么该变量初始化为 SQL 空值。 CONSTANT选项避免了该变量被赋值,这样其数值在该块的范围内保持常量。 如果声明了NOT NULL,那么赋予NULL数值将导致一个运行时错误。 所以所有声明为NOT NULL的变量还必须声明一个非空的缺省值。
缺省值是在每次进入该块的时候计算的。因此,如果把 now() 赋予一个类型为 timestamp 的变量会令变量拥有函数实际调用的时间,而不是函数预编译的时间。
例子∶
quantity integer DEFAULT 32; url varchar := 'http://mysite.com'; user_id CONSTANT integer := 10;
传递给函数的参数都是用 $1,$2,等等这样的标识符。 为了增加可读性,我们可以为 $n 参数名声明别名。 然后别名或者数字标识符都可以指向参数值。
有两种创建别名的方法,比较好的是在 CREATE FUNCTION 命令里给出参数名, 比如:
CREATE FUNCTION sales_tax(subtotal real) RETURNS real AS $$ BEGIN RETURN subtotal * 0.06; END; $$ LANGUAGE plpgsql;
另外一个方法,是 PostgreSQL 8.0 以前的唯一的方法, 是明确地声明为别名,使用声明语法
name ALIAS FOR $n;
这个风格的同一个例子看起来像下面这样
CREATE FUNCTION sales_tax(REAL) RETURNS real AS $$ DECLARE subtotal ALIAS FOR $1; BEGIN RETURN subtotal * 0.06; END; $$ LANGUAGE plpgsql;
更多例子:
CREATE FUNCTION instr(varchar,integer) RETURNS integer AS $$ DECLARE v_string ALIAS FOR $1; index ALIAS FOR $2; BEGIN -- 这里放一些计算 END; $$ LANGUAGE plpgsql; CREATE FUNCTION concat_selected_fields(in_t tablename) RETURNS text AS $$ BEGIN RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7; END; $$ LANGUAGE plpgsql;
如果一个 PL/pgSQL 函数的返回类型声明为一个多态类型 (anyelement 或者 anyarray),那么就会创建一个特殊的参数, $0。它的数据类型是函数的实际返回类型,和从实际输入类型推导推导类型一样 (参阅 Section 31.2.5)。 这样就允许函数访问它的实际返回类型,像 Section 35.4.2 里显示的那样。 $0 初始化为空,并且可以被函数修改,所以,如果需要,它可以用于保存返回值, 虽然这并非必须的。$0 还可以给予一个别名。比如,这个函数可以在任何有 + 操作符的数据类型上运转:
CREATE FUNCTION add_three_values(v1 anyelement, v2 anyelement, v3 anyelement) RETURNS anyelement AS $$ DECLARE result ALIAS FOR $0; BEGIN result := v1 + v2 + v3; RETURN result; END; $$ LANGUAGE plpgsql;
variable%TYPE
%TYPE 提供一个变量或者表字段的数据类型。 你可以用这个声明将要保存数据库数值的变量。比如,假如你在 users 表里面有一个字段叫 user_id。要声明一个和 users.user_id 类型相同的变量,你可以写:
user_id users.user_id%TYPE;
通过使用 %TYPE,你必须知道你引用的结构的数据类型, 并且,最重要的是,如果被引用项的数据类型在将来变化了(比如:你把 user_id 的类型从 integer 改成 real),你也不需要修改你的函数定义。
%TYPE 对多态的函数特别有用,因为内部变量的数据类型可能在不同调用中是不一样的。 我们可以通过给函数的参数或者结果占位符附加 %TYPE 的方法来创建合适的变量。
name table_name%ROWTYPE; name composite_type_name;
一个复合类型变量叫做行变量(或者row-type变量)。 这样的一个变量可以保存一次SELECT或者 FOR命令结果的完整一行,只要命令的字段集匹配该变量声明的类型。 行数值的独立的字段是使用常用的点表示法访问的,比如 rowvar.field。
一个行变量可以声明为和一个现有的表或者视图的行类型相同,方法是使用 table_name%ROWTYPE 表示法; 或者你也可以声明它的类型是一个复合类型的名字。(因为每个表都有一个相关联的同名数据类型, 在 PostgreSQL 里实在是无所谓你写不写 %ROWTYPE。但是有 %ROWTYPE 的形式移植性更好。)
函数的参数可以是复合类型(表的完整行)。这个时候, 对应的标识符 $n 将是一个行变量,并且可以从中选取字段,比如 $1.user_id。
在一个行类型的变量中,只可以访问用户定义的表中行的属性, 不包括 OID 或者其他系统属性(因为该行可能来自一个视图)。 该行类型的数据域继承表中象 char(n) 这种类型字段的尺寸和精度。
这里是一个使用复合类型的例子:
CREATE FUNCTION merge_fields(t_row tablename) RETURNS text AS $$ DECLARE t2_row table2name%ROWTYPE; BEGIN SELECT * INTO t2_row FROM table2name WHERE ... ; RETURN t_row.f1 || t2_row.f3 || t_row.f5 || t2_row.f7; END; $$ LANGUAGE plpgsql; SELECT merge_fields(t.*) FROM tablename t WHERE ... ;
name RECORD;
纪录变量类似行类型变量,但是它们没有预定义的结构。 它们在SELECT或者FOR命令中获取实际的行结构。 一个行变量的子结构可以在每次赋值的时候改变。 这样做的一个结果是:在一个记录变量被赋予数值之前,它没有子结构, 并且任何对其中的数据域进行访问的企图都将产生一个运行时错误。
请注意 RECORD 不是真正的数据类型,只是一个占位符。 我们还应该意识到在把一个 PL/pgSQL 函数声明为返回record类型的时候, 它和一个记录变量的概念并不完全相同,即使这个函数可能使用一个记录变量保存它的结果也如此。 在两种情况下,在书写函数的时候,实际的行结构都是不知道的,但是对于返回 record 的函数来说, 实际的结构是在调用它的查询被分析的时候决定的,而行变量可以在运行中改变其行结构。
RENAME oldname TO newname;
你可以用 RENAME 声明修改一个变量,记录或者行的名字。 如果 NEW 或者 OLD 在个触发器过程里被另外一个名字引用, 那么这个东西就很有用。又见 ALIAS。
例子∶
RENAME id TO user_id; RENAME this_var TO that_var;
注意: RENAME 在PostgreSQL7.3 里好像有问题。修补这个毛病的优先级比较低, 因为 ALIAS 覆盖了大多数 RENAME 的实际用途。