正如我们想象的那样, 定义新类型的一部分工作是定义描述(该类型)特征的函数. 因此,我们可能可以只定义 一个新函数而不定义新类型,反过来却不行.所以,我们先描述如何给 Postgres 增加新函数,然后再描述如 何增加新类型.
Postgres SQL 提供三种类型的函数:
查询语言函数(用 SQL 写的函数)
过程语言函数(用诸如 PLTCL 或 PLSQL 这样的语言写的函数)
编程语言函数(用类似C这样编译的编程语言写的函数)
SQL 函数执行一个任意 SQL 查询的列表,返回列表里最后一个查询的结果。 SQL 函数通常返回结果集。如果它 们的返回类型没有声明为 setof, 那么将返回最后一条查询结果的任意元素。
跟在 AS 后面的 SQL 函数体应该是一个用空白字符分隔和 用单引号括起来的查询列表。 要注意在查询里面的引 号必须用前面带反斜杠的方法转意。
SQL 函数的参数在查询里可以用 $n 语法引用: $1指第一个参数,$2 指第二个参数,以此类推。 如果参数是 复合类型,那么可以用点表示法 (例如,"$1.emp")访问参数里的字段或者激活函数。
看看下面这个简单的 SQL 函数的例子, 它将用于对一个银行帐号做扣款(借记消费 debit)动作:
CREATE FUNCTION tp1 (int4, float8) RETURNS int4 AS 'UPDATE bank SET balance = bank.balance - $2 WHERE bank.acctountno = $1; SELECT 1;' LANGUAGE 'sql';一个用户可以象下面这样用这个函数给帐户 17 扣款 $100.00:
SELECT tp1( 17,100.0);
下面的更有意思的例子接受一个类型为 EMP 的参数,并且检索多个结果:
CREATE FUNCTION hobbies (EMP) RETURNS SETOF hobbies AS 'SELECT hobbies.* FROM hobbies WHERE $1.name = hobbies.person' LANGUAGE 'sql';
最简单的 SQL 函数可能是不带参数,只是返回一个基本类型如 int4 的函数:
CREATE FUNCTION one() RETURNS int4 AS 'SELECT 1 as RESULT;' LANGUAGE 'sql'; SELECT one() AS answer; +-------+ |answer | +-------+ |1 | +-------+
注意我们给函数定义了目标列(名称为 RESULT), 但是激活函数的查询语句的目标列覆盖了函数的目标 列.因此,结果的标记是 answer 而不是 one .
定义以基本类型为参数的 SQL 函数几乎一样简单, 注意我们在函数内如何用$1和$2使用参数:
CREATE FUNCTION add_em(int4, int4) RETURNS int4 AS 'SELECT $1 + $2;' LANGUAGE 'sql'; SELECT add_em(1, 2) AS answer; +-------+ |answer | +-------+ |3 | +-------+
当我们声明的函数用复合类型(如 EMP)做参数时, 我们不仅要声明我们需要哪个参数(像上面我们使用 $1和$2一样),而且要声明参数的字段.比如, 把 double_salary 做为计算你薪水翻番之后的数值的函数:
CREATE FUNCTION double_salary(EMP) RETURNS int4 AS 'SELECT $1.salary * 2 AS salary;' LANGUAGE 'sql'; SELECT name, double_salary(EMP) AS dream FROM EMP WHERE EMP.cubicle ~= point '(2,1)'; +-----+-------+ |name | dream | +-----+-------+ |Sam | 2400 | +-----+-------+
注意这里 $1.salary 语法的使用.在开始说明返回复合类型的函数之前, 我们必须先介绍用于映射字段的函数表示法.我们可 以用一个简单的方法解释这些: 我们可以互换地使用 attribute(class) 和 class.attribute 两种表达方式:
-- -- 这是与下面语句一样的: -- SELECT EMP.name AS youngster FROM EMP WHERE EMP.age < 30 -- SELECT name(EMP) AS youngster FROM EMP WHERE age(EMP) < 30; +----------+ |youngster | +----------+ |Sam | +----------+
不过,我们呆会儿就会看到不总是这种情况. 这种函数表示法在我们希望使用的函数返回单条记录时是很重要的. 此时我们 在函数里面一个字段一个字段地组装整条记录. 下面是返回单条 EMP 记录的函数例子:
CREATE FUNCTION new_emp() RETURNS EMP AS 'SELECT text ''None'' AS name, 1000 AS salary, 25 AS age, point ''(2,2)'' AS cubicle' LANGUAGE 'sql';
在这个例子中我们给每个字段都赋予了一个常量, 当然我们可以用任何计算或表达式来代替这些常量. 定义这样的函数可能需 要一点点技巧.下面是一些比较重要的注意事项:
目标列表的顺序必须和你用 CREATE TABLE 语句定义复合类型时字段出现的顺序完全一样.
你必须对表达式进行类型转换以匹配复合类型的定义. 否则你将看到下面的错误信息:
ERROR: function declared to return emp returns varchar instead of text at column 1
当我们调用了一个返回整条记录的函数时,我们不能检索整条记录. 我们要么是从该记录中映射出一个字段,要么是 把整条记录传递给另外一个函数.
SELECT name(new_emp()) AS nobody; +-------+ |nobody | +-------+ |None | +-------+
通常我们必须把函数的返回值映射到字段里, 使用这种函数语法是因为分析器在分析函数调用时,无法正确分析与函 数相联的'点'的语法.
SELECT new_emp().name AS nobody; NOTICE:parser: syntax error at or near "."
在 SQL 查询语言里的任何命令的集合都可以打包在一起, 定义为函数. 这些命令可以包含更新动作(也就是说, INSERT,UPDATE,和 DELETE),就象可以使用 SELECT 查询一样.不过, 最后的命令必须是一条返回类型与所声明的函数返 回类型的一致的 SELECT语句。
CREATE FUNCTION clean_EMP () RETURNS int4 AS 'DELETE FROM EMP WHERE EMP.salary <= 0; SELECT 1 AS ignore_this;' LANGUAGE 'sql'; SELECT clean_EMP(); +--+ |x | +--+ |1 | +--+