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

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

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2
历史版本PostgreSQL 7.2 已于 2007 年 2 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本。

23.5. 基本语句 #

在本节和接下来的几节中,我们描述PL/pgSQL 显式理解的所有语句类型。任何没有被识别为这些语句类型之一的 东西都被假定为一个 SQL 查询,并被发送到主数据库引擎执行 (在替换语句中使用的任何PL/pgSQL变量 之后)。因此,例如 SQL 的INSERT、UPDATE 和DELETE命令可以被认为是PL/pgSQL 的语句,但它们没有在这里专门列出。

23.5.1. 赋值 #

把一个值赋给变量或行/记录字段写作:

identifier := expression;

如上所述,这类语句中的表达式通过发送给主数据库引擎的 SQL SELECT命令求值。表达式必须产生一个单一值。

如果表达式的结果数据类型与变量的数据类型不匹配,或者变量 具有特定的尺寸/精度(如char(20)),结果值将被 PL/pgSQL解释器使用结果类型的输出函数 和变量类型的输入函数隐式转换。注意,如果结果值的字符串形式 不被输入函数接受,这可能导致输入函数产生运行时错误。

例子:

user_id := 20;
tax := subtotal * 0.06;

23.5.2. SELECT INTO #

产生多列(但只有一行)结果的 SELECT 命令可以赋给一个记录 变量、行类型变量或标量变量列表。写法是:

SELECT INTO target expressions FROM ...;

其中target可以是一个记录变量、一个行 变量,或者一个由简单变量和记录/行字段组成的逗号分隔列表。 注意这与PostgreSQL对 SELECT INTO 的通常解释 ——INTO 的目标是一张新创建的表——完全不同。(如果你想在 PL/pgSQL函数内部从 SELECT 结果创建表, 请使用CREATE TABLE ... AS SELECT语法。)

如果用一行或一个变量列表作为目标,所选中的值必须与目标的 结构完全匹配,否则会发生运行时错误。当目标是记录变量时, 它会自动把自己配置成查询结果列的行类型。

除 INTO 子句外,该 SELECT 语句与普通的 SQL SELECT 查询相同, 可以使用 SELECT 的全部能力。

如果 SELECT 查询返回零行,NULL 会被赋给目标。如果 SELECT 查询返回多行,第一行会被赋给目标而其余的行被丢弃。(注意, 除非你使用了 ORDER BY,否则“第一行”并没有良好 的定义。)

目前,INTO 子句几乎可以出现在 SELECT 查询的任何位置,但 建议像上面展示的那样把它紧放在 SELECT 关键字之后。 PL/pgSQL的未来版本可能不会这么 宽容地对待 INTO 子句的位置。

有一个名为 FOUND 的boolean类型特殊变量,可以 在 SELECT INTO 之后立即使用它来检查赋值是否成功(也就是 SELECT 是否至少返回了一行)。例如,

SELECT INTO myrec * FROM EMP WHERE empname = myname;
IF NOT FOUND THEN
    RAISE EXCEPTION ''employee % not found'', myname;
END IF;

另一种办法是,你可以用 IS NULL(或 ISNULL)条件来测试 RECORD/ROW 结果是否为 NULL。注意没有办法判断是否还有更多 的行被丢弃。

DECLARE
    users_rec RECORD;
    full_name varchar;
BEGIN
    SELECT INTO users_rec * FROM users WHERE user_id=3;

    IF users_rec.homepage IS NULL THEN
        -- user entered no homepage, return "http://"

        RETURN ''http://'';
    END IF;
END;

23.5.3. 执行没有结果的表达式或查询 #

有时你会想求值一个表达式或查询但丢弃其结果(典型情况是 正在调用一个有有用的副作用但没有有用的结果值的函数)。在 PL/pgSQL中要做到这一点,使用 PERFORM 语句:

PERFORM query;

它执行一个SELECT query并丢弃结果。 PL/pgSQL变量照常被替换进查询中。

注意

人们可能以为不带 INTO 子句的 SELECT 就能实现这个结果,但 目前唯一被接受的做法是 PERFORM。

一个例子:

PERFORM create_mv(''cs_session_page_requests_mv'',''
     SELECT   session_id, page_id, count(*) AS n_hits,
              sum(dwell_time) AS dwell_time, count(dwell_time) AS dwell_count
     FROM     cs_fact_table
     GROUP BY session_id, page_id '');

23.5.4. 执行动态查询 #

你经常会想在PL/pgSQL函数内部生成动态 查询,也就是每次执行时会涉及不同的表或不同数据类型的查询。 PL/pgSQL通常为查询缓存计划的做法在 这类场景下不起作用。为了处理这类问题,提供了 EXECUTE 语句:

EXECUTE query-string;

其中query-string是一个产生字符串 (类型为text)的表达式,该字符串包含要执行的 query。这个字符串被原样送入 SQL 引擎。

特别注意,查询字符串上的PL/pgSQL变量 不会被替换。变量的值必须在构造查询字符串时就被插入其中。

在使用动态查询时,你必须面对PL/pgSQL中单引号 的转义问题。请参阅第 23.11 节中的表格, 那里有能为你节省一些力气的详细解释。

与PL/pgSQL中的所有其他查询不同,由 EXECUTE 语句运行的query不会在服务器的生命期 内只准备和保存一次。相反,query在 语句每次运行时都会被重新准备。 query-string可以在过程内动态创建, 以便对可变的表和字段执行操作。

SELECT 查询的结果会被 EXECUTE 丢弃,而且 EXECUTE 中目前不 支持 SELECT INTO。因此,从动态创建的 SELECT 中提取结果的唯一 办法是使用稍后描述的 FOR-IN-EXECUTE 形式。

一个例子:

EXECUTE ''UPDATE tbl SET ''
        || quote_ident(fieldname)
        || '' = ''
        || quote_literal(newvalue)
        || '' WHERE ...'';

这个例子展示了quote_ident(TEXT) 和quote_literal(TEXT)函数的用法。 包含字段和表标识符的变量应当传给 quote_ident()函数。包含动态查询字符串的 字面量成分的变量应当传给quote_literal()。 这两个函数都会采取适当的步骤,返回被单引号或双引号括起、 且内嵌的特殊字符被正确转义的输入文本。

下面是一个大得多的动态查询和 EXECUTE 的例子:

CREATE FUNCTION cs_update_referrer_type_proc() RETURNS INTEGER AS '
DECLARE
    referrer_keys RECORD;  -- Declare a generic record to be used in a FOR
    a_output varchar(4000);
BEGIN 
    a_output := ''CREATE FUNCTION cs_find_referrer_type(varchar,varchar,varchar) 
                  RETURNS VARCHAR AS '''' 
                     DECLARE 
                         v_host ALIAS FOR $1; 
                         v_domain ALIAS FOR $2; 
                         v_url ALIAS FOR $3;
                     BEGIN ''; 

    -- 
    -- Notice how we scan through the results of a query in a FOR loop
    -- using the FOR <record> construct.
    --

    FOR referrer_keys IN SELECT * FROM cs_referrer_keys ORDER BY try_order LOOP
        a_output := a_output || '' IF v_'' || referrer_keys.kind || '' LIKE '''''''''' 
                 || referrer_keys.key_string || '''''''''' THEN RETURN '''''' 
                 || referrer_keys.referrer_type || ''''''; END IF;''; 
    END LOOP; 
  
    a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE ''''plpgsql'''';''; 
 
    -- This works because we are not substituting any variables
    -- Otherwise it would fail. Look at PERFORM for another way to run functions
    
    EXECUTE a_output; 
END; 
' LANGUAGE 'plpgsql';

23.5.5. 获取结果状态 #

GET DIAGNOSTICS variable = item [ , ... ] ;

这条命令允许检索系统状态指示器。每个 item都是一个关键字,标识要赋给指定 变量的状态值(该变量应当具有接收它的正确数据类型)。当前可用的 状态项有:ROW_COUNT,发送到SQL 引擎的最后一条SQL查询所处理的行数;以及 RESULT_OID,最近的SQL查询插入的 最后一行的 Oid。注意RESULT_OID只在 INSERT 查询 之后有用。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。