PostgreSQL 不支持像 Oracle 这样的数据库那样的 存储过程 ,但它支持 存储函数 。在这篇文章中,我研究了一些策略,可以使在 PostgreSQL 中使用存储函数(存储函数及其调用代码均用 PL/pgSQL 编写)就像使用 存储过程 一样。这些简单的方法允许开发人员以与存储过程的使用更一致的方式使用 PostgreSQL 存储函数。
存储过程和存储函数非常相似,事实上,我经常听到术语“存储过程”可互换地用于存储过程和存储函数。出于本文的目的,两者之间的本质区别可以概括为:
- 函数是用 FUNCTION 关键字创建的,过程是用 PROCEDURE 关键字创建的。
-
存储过程不返回值,但存储函数返回单个值。
- 存储函数的返回值可以在 SELECT 语句中使用。
因为PostgreSQL PL/pgSQL只支持存储函数,定义的函数需要声明返回类型。幸运的是,对于我们模拟的“ 存储过程 ”,我们可以 将 void 声明为返回类型 。下面的代码清单展示了用 PL/pgSQL 编写的“Hello World”实现。
CREATE OR REPLACE FUNCTION helloWorld(name text) RETURNS void AS $helloWorld$
DECLARE
BEGIN
RAISE LOG 'Hello, %', name;
END;
$helloWorld$ LANGUAGE plpgsql;
通过编写返回类型为 void 的 PostgreSQL 存储函数,我们现在可以从客户端调用它。在这种情况下,我将研究从其他 PL/pgSQL 代码调用存储函数的三种方法。
PL/pgSQL:通过 SELECT 语句调用函数
在 PL/pgSQL 代码中调用存储函数的一种方法是使用 SELECT INTO 。最明显的缺点是,在类似过程的函数返回 void 的情况下,没有选择任何有用的东西,因此必须忽略被选择的变量。下一个代码清单演示了如何使用 SELECT INTO 来调用类似过程的函数。这个例子中的变量,称为“dumped”,不会有任何有用的选择,但这个语句成功调用了存储的函数。除了此处显示的行之外,我还需要在 DECLARE 部分中添加一行来声明“转储”变量。
CREATE OR REPLACE FUNCTION helloWorld(name text) RETURNS void AS $helloWorld$
DECLARE
BEGIN
RAISE LOG 'Hello, %', name;
END;
$helloWorld$ LANGUAGE plpgsql;
PL/pgSQL:通过变量赋值调用函数
PL/pgSQL 赋值运算符 提供了另一种调用类过程存储函数的方法。与前面的示例一样,此方法需要在 DECLARE 部分中声明一个变量(“忽略”),然后为该变量分配返回 void 的函数的结果,从而使其实际上也是一个一次性变量。
CREATE OR REPLACE FUNCTION helloWorld(name text) RETURNS void AS $helloWorld$
DECLARE
BEGIN
RAISE LOG 'Hello, %', name;
END;
$helloWorld$ LANGUAGE plpgsql;
PL/pgSQL:使用 PERFORM 显式忽略返回值
PL/pgSQL 命令 PERFORM 在调用类似过程的存储函数时提供了一些语法优势。此命令不需要声明 PL/pgSQL 变量。这节省了声明变量的行,并避免了设置一个从未真正设置过的变量的假装。它实际上只是 SELECT 的快捷方式,但它 在语法上更甜美 并且使代码更具可读性,因为代码维护者不必弄清楚看似进行赋值的语句实际上并没有这样做。
CREATE OR REPLACE FUNCTION helloWorld(name text) RETURNS void AS $helloWorld$
DECLARE
BEGIN
RAISE LOG 'Hello, %', name;
END;
$helloWorld$ LANGUAGE plpgsql;
结论
尽管 PostgreSQL 只支持存储的“函数”(而不支持存储的“过程”),但它提供的语法允许函数具有类似过程的特性。通过允许存储函数返回 void 并通过不期望结果值的 PERFORM 从 PL/pgSQL 代码调用,PostgreSQL 允许客户端代码看起来好像在调用存储过程而不是存储函数。