↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

不受支持的版本: 6.3
历史版本PostgreSQL 6.3 已于 2003 年 3 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本手册首页。

第 31 章 扩展 SQL:函数

事实证明,定义新类型的一部分工作就是定义描述其行为的函数。因此,虽然可以不定义新类型就定义新函数,反过来却不成立。所以我们在描述如何向 Postgres 添加新类型之前先描述如何添加新函数。 Postgres SQL 提供两类函数:查询语言函数(用 SQL 编写的函数)和编程语言函数(用 C 等编译型编程语言编写的函数)。每类函数都可以接受基本类型、复合类型或它们的某种组合作为参数。此外,两类函数都可以返回基本类型或复合类型。定义 SQL 函数更容易,所以我们从它开始。本节的示例也可以在 funcs.sql 和 C-code/funcs.c 中找到。

31.1. 查询语言(SQL)函数

31.1.1. 基本类型上的 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      |
         +-------+

31.1.2. 复合类型上的 SQL 函数

指定带复合类型(如 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\'::char16 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 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。