pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
目录
事实证明,定义新类型的一部分工作就是定义描述其行为的函数。因此,虽然可以不定义新类型就定义新函数,反过来却不成立。所以我们在描述如何向 Postgres 添加新类型之前先描述如何添加新函数。 Postgres SQL 提供两类函数:查询语言函数(用 SQL 编写的函数)和编程语言函数(用 C 等编译型编程语言编写的函数)。每类函数都可以接受基本类型、复合类型或它们的某种组合作为参数。此外,两类函数都可以返回基本类型或复合类型。定义 SQL 函数更容易,所以我们从它开始。本节的示例也可以在 funcs.sql 和 C-code/funcs.c 中找到。
最简单的 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.dept = 'toy';
+-----+-------+
|name | dream |
+-----+-------+
|Sam | 2400 |
+-----+-------+
注意语法 $1.salary 的使用。在进入返回复合类型的函数这一主题之前,我们必须先介绍投影属性的函数记法。简单的解释是:attribute(class) 和 class.attribute 这两种记法通常可以互换使用。
--
-- this is the same as:
-- 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 \'None\'::text AS name,
1000 AS salary,
25 AS age,
\'none\'::text AS dept;'
LANGUAGE 'sql';
在本例中,我们为每个属性都指定了常量值,但这些常量可以换成任何计算或表达式。定义这样的函数可能有些棘手。较重要的一些注意事项如下:
查询中的目标列表顺序必须与定义该复合类型的 CREATE TABLE 语句(或执行 .* 查询时)中属性出现的顺序完全相同。
你必须(使用 ::)非常小心地对表达式进行类型转换,否则会看到如下错误:
WARN::function declared to return type EMP does not retrieve (EMP.*)
调用返回实例的函数时,我们无法检索整个实例。我们必须要么从实例中投影出一个属性,要么把整个实例传递给另一个函数。
SELECT name(new_emp()) AS nobody;
+-------+
|nobody |
+-------+
|None |
+-------+
一般而言,我们必须使用函数语法投影函数返回值的属性,原因就是解析器还不理解另一种(点)语法与函数调用组合使用做投影。
SELECT new_emp().name AS nobody;
WARN: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 |
+--+
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。