RETURN subtotal * 0.06;
END;
$$ LANGUAGE plpgsql;
3). 对于输出参数而言,我们仍然可以遵守1)和2)中的规则。
CREATE FUNCTION sales_tax(subtotal real, OUT tax real) AS $$
BEGIN www.2cto.com
tax := subtotal * 0.06;
END;
$$ LANGUAGE plpgsql;
4). 如果PL/pgSQL函数的返回类型为多态类型(anyelement或anyarray),那么函数就会创建一个特殊的参数:$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;
2. 拷贝类型:
见如下形式的变量声明:
variable%TYPE
%TYPE表示一个变量或表字段的数据类型,PL/pgSQL允许通过该方式声明一个变量,其类型等同于variable或表字段的数据类型,见如下示例:
user_id users.user_id%TYPE;
在上面的例子中,变量user_id的数据类型等同于users表中user_id字段的类型。
通过使用%TYPE,一旦引用的变量类型今后发生改变,我们也无需修改该变量的类型声明。最后需要说明的是,我们可以在函数的参数和返回值中使用该方式的类型声明。
3. 行类型:
见如下形式的变量声明:
name table_name%ROWTYPE;
name composite_type_name;
table_name%ROWTYPE表示指定表的行类型,我们在创建一个表的时候,PostgreSQL也会随之创建出一个与之相应的复合类型,该类型名等同于表名,因此,我们可以通过以上两种方式来声明行类型的变量。由此方式声明的变量,可以保存SELECT返回结果中的一行。如果要访问变量中的某个域字段,可以使用点表示法,如rowvar.field,但是行类型的变量只能访问自定义字段,无法访问系统提供的隐含字段,如OID等。对于函数的参数,我们只能使用复合类型标识变量的数据类型。最后需要说明的是,推荐使用%ROWTYPE的声明方式,这样可以具有更好的可移植性,因为在
Oracle的PL/SQL中也存在相同的概念,其声明方式也为%ROWTYPE。见如下示例:
CREATE FUNCTION merge_fields(t_row table1) RETURNS text AS $$
DECLARE
t2_row table2%ROWTYPE;
BEGIN
SELECT * INTO t2_row FROM table2 WHERE id = 1 limit 1;
RETURN t_row.f1 || t2_row.f3 || t_row.f5 || t2_row.f7;
END; www.2cto.com
$$ LANGUAGE plpgsql;
4. 记录类型:
见如下形式的变量声明:
name RECORD;
记录变量类似于行类型变量,但是它们没有预定义的结构,只能通过SELECT或FOR命令来获取实际的行结构,因此记录变量在被初始化之前无法访问,否则将引发运行时错误。
注:RECORD不是真正的数据类型,只是一个占位符。
四、基本语句:
1. 赋值:
PL/pgSQL中赋值语句的形式为:identIFier := expression,等号两端的变量和表达式的类型或者一致,或者可以通过PostgreSQL的转换规则进行转换,否则将会导致运行时错误,见如下示例:
user_id := 20;
tax := subtotal * 0.06;
2. SELECT INTO:
通过该语句可以为记录变量或行类型变量进行赋值,其表现形式为:SELECT INTO target select_expressions FROM ...,该赋值方式一次只能赋值一个变量。表达式中的target可以表示为是一个记录变量、行变量,或者是一组用逗号分隔的简单变量和记录/行字段的列表。select_expressions以及剩余部分和普通SQL一样。
如果将一行或者一个变量列表用做目标,那么选出的数值必需精确匹配目标的结构,否则就会产生运行时错误。如果目标是一个记录变量,那么它自动将自己构造成命令结果列的行类型。如果命令返回零行,目标被赋予空值。如果命令返回多行,那么将只有第一行被赋予目标,其它行将被忽略。在执行SELECT INTO语句之后,可以通过检查内置变量FOUND来判断本次赋值是否成功,如:
SELECT INTO myrec * FROM emp WHERE empname = myname;
IF NOT FOUND THEN
RAISE EXCEPTION 'employee % not found', myname;
END IF;
要测试一个记录/行结果是否为空,可以使用IS NULL条件进行判断,但是对于返回多条记录的情况则无法判断,如:
DECLARE
users_rec RECORD;
BEGIN
SELECT INTO users_rec * FROM users WHERE user_id = 3;
IF users_rec.homepage IS NULL THEN
RETURN 'http://';
END IF;
END;
3. 执行一个没有结果的表达式或者命令:
在调用一个表达式或执行一个命令时,如果对其返回的结果不感兴趣,可以考虑使用PERFORM语句:PERFORM query,该语句将执行PERFORM之后的命令并忽略其返回的结果。其中query的写法和普通的SQL SELECT命令是一样的,只是把开头的关键字SELECT替换成PERFORM,如:
PERFORM create_mv('cs_session_page_requests_mv', my_query);
4. 执行动态命令:
如果在PL/pgSQL函数中操作的表或数据类型在每次调用该函数时都可能会发生变化,在这样的情况下,可以考虑使用PL/pgSQL提供的EXECUTE语句:EXECUTE command-string [ INTO target ],其中command-string