正如我们想象的那样, 定义新类型的一部分工作是定义描述(该类型)特征的函数. 因此,我们可能可以只定义 一个新函数而不定义新类型,反过来却不行.所以,我们先描述如何给 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 |
+--+