所有在块里使用的变量,行和记录 都必须在一个块的声明段里声明.(唯一的例外是 一个 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 NULL 值.
CONSTANT 选项避免了该变量被赋值,这样其数值在该块的范围内保持常量. 如果声明了 NOT NULL,那么赋予 NULL 数值将导致一个运行时错误. 所以所有声明为 NOT NULL 的变量还必须声明一个非 NULL 的缺省值.
缺省值是在每次进入该块的时候计算的.因此,举例来说, 把'now'赋予一个类型为 TIMESTAMP 的变量会令变量拥有函数实际调用 的时间,而不是函数预编译的时间.
例子∶
quantity INTEGER DEFAULT 32; url VARCHAR := ''http://mysite.com''; user_id CONSTANT INTEGER := 10;
name ALIAS FOR $n;
传递给函数的参数都是用 $1,$2, 等等这样的标识符.为了增加可读性,我们可以为 $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 use_many_fields(tablename) RETURNS TEXT AS ' DECLARE in_t ALIAS FOR $1; BEGIN RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7; END; ' LANGUAGE 'plpgsql';
name tablename%ROWTYPE;
一个复合类型变量叫做行变量(或者 row-type变量). 变量.这样的一个变量可以保存一次 SELECT 或者 FOR 查询结果的完整一行,只要查询的字段集匹配该变量声明的类型. 行数值的独立的字段是使用常用的点表示法访问的,比如 rowvar.field.
目前,一个行变量只能用 %ROWTYPE 表示法声明; 尽管我们可能认为一个光表名也可以做类型声明用,但在 PL/pgSQL 函数里是不行的.
函数的参数可以是复合类型(表的完整行).这个时候, 对应的标识符 $n 将是一个行变量,并且可以从中选取字段, 比如 $1.user_id.
在一个行类型的变量中,只可以访问用户定义的表中行的属性, 不包括 OID 或者其他系统属性(因为该行可能来自一个视图). 该行类型的数据域继承表中象 char(n) 这种类型字段的 尺寸和精度.
CREATE FUNCTION use_two_tables(tablename) RETURNS TEXT AS ' DECLARE in_t ALIAS FOR $1; use_t table2name%ROWTYPE; BEGIN SELECT * INTO use_t FROM table2name WHERE ... ; RETURN in_t.f1 || use_t.f3 || in_t.f5 || use_t.f7; END; ' LANGUAGE 'plpgsql';
name RECORD;
纪录变量类似行类型变量,但是它们没有预定义的结构. 它们在 SELECT 或者 FOR 命令中获取实际的行结构.一个行变量的 子结构可以在每次赋值的时候修改.这样做的一个结果是∶在一个记录变量 被赋予数值之前,它没有子结构,并且任何对其中的数据域 进行访问的企图都将产生一个运行时错误.
请注意 RECORD 不是真正的数据类型,只是一个占位符.
使用 %TYPE 和 %ROWTYPE 属性, 你可以把变量声明为与另外一个数据库项相同的数据类型或结构(比如∶ 一个表的域).
%TYPE 给我们提供了一个变量或者数据库列的数据类型. 你可以用这个关键字声明那些需要保存数据库数值的变量. 举例来说,让我们假设你有一个叫 user_id 的列 在你的 users 表里.要声明一个和 users.user_id 相同的数据类型, 你可以∶
user_id users.user_id%TYPE;
通过使用 %TYPE,你就不需要知道你引用的 结构的数据类型,最重要的是,如果被引用项的数据类型在将来 变化了(比如你把表定义列的 user_id 从 INTEGER 改成 REAL),那你也 用不着修改你的函数定义.
%ROWTYPE 提供了一个对应特定表的一整行的复合类型. table 必须 是该数据库里一个现存的表或者视图的名字.
DECLARE users_rec users%ROWTYPE; user_id users.user_id%TYPE; BEGIN user_id := users_rec.user_id; ... CREATE FUNCTION does_view_exist(INTEGER) RETURNS bool AS ' DECLARE key ALIAS FOR $1; table_data cs_materialized_views%ROWTYPE; BEGIN SELECT INTO table_data * FROM cs_materialized_views WHERE sort_key=key; IF NOT FOUND THEN RETURN false; END IF; RETURN true; END; ' LANGUAGE 'plpgsql';
RENAME oldname TO newname;
你可以用 RENAME 声明修改一个变量,记录或者行的名字. 如果 NEW 或者 OLD 在个触发器过程里被另外一个名字引用, 那么这个东西就很有用.又见 ALIAS.
例子∶
RENAME id TO user_id; RENAME this_var TO that_var;
注意: RENAME 在PostgreSQL7.3 里好像有问题.修补这个毛病的优先级比较低, 因为 ALIAS 覆盖了大多数 RENAME 的实际用途.