第一,执行语句
在调用一个表达式或者一个执行命令时,如果对它返回的数据不感兴趣,我们可以考虑使用PERFORM语句,也就是PERFORM query的格式,它会执行PERFORM之后的命令,但是忽略其返回的结果。而且其中的query的写法和普通的sql语句是一样的,只是把开头的关键字select 替换为perform即可。
如果我们在执行plpgsql函数中操作的表或者数据类型在每次调用该函数时都可能会发生变化,我们可以使用plpgsql提供的execute语句,格式如下:execute 语句 [into target],其中语句是用一段文本表示的表达式,它包含要执行的命令。而target则是一个记录变量、行变量或者一组用逗号分隔的简单变量和记录、行域的列表。它不会进行任何的plpgsql的变量代换,变量的数值必需在构造命令字符串的时候插入到该字符串中。
一个execute语句运行的命令在服务器内并不会只prepare和保存一次,而是在它每次运行的时候,都会prepare一次。因此命令字符串可以在函数里面动态生成以便于对于各种不同的表和字段进行操作,从而提高函数的灵活性。
第二,控制结构
我们可以使用return expression来终止当前的函数,然后再将expression的值返回给调用者。如果返回简单类型,那么可以使用任何表达式,同时表达式的类型也将自动转换为函数的返回类型。如果要返回一个复合类型的数值,则必须让表达式返回记录或者匹配的行变量。
而对于return next 来说,它直到执行到不带参数的return时才表示该函数结束,因此对于return next来说,它实际上并不从函数中返回,它只是简单的把表达式的值保存起来,然后继续执行plpgsql函数里的下一条语句,随着return next命令的迭代执行,结果集最终被建立起来,而它的调用方式一般也是select * from some_func();它可以被放在from子句中被当做数据源使用,而且需要指出的是,如果数据源很大,那么该方式来构建结果集会导致很大的性能损失。
对于条件语句,我们通常使用的格式有:
(1)if 条件 then 语句 end if;
(2) if 条件 then 语句 else 语句 endif;
(3) if 条件 then 语句 elseif 条件 then 语句 elseif 条件 then 语句 else 语句 endif;
对于循环,通常使用的格式有:
(1)loop 语句 end loop [标号] ;其中loop定义一个无条件的循环,直到exit或者return语句终止。可选的label可以由exit和continue语句使用,用于在嵌套循环中声明应该应用于哪一层循环。
(2)exit [label] [when expression]; 如果没有给出label,就退出最内层的循环,然后执行跟在END LOOP后面的语句,如果给出了label,它必须是当前或者更高层的嵌套循环块或者语句块的标签。之后该命名快或者循环就会终止,而控制则直接转到对应循环块的END后面的语句上。如果声明了when,则exit命令只有在expression为真的时候才会被执行,否则将直接执行exit后面的语句。通常我们的使用格式是:loop 其他语句 exit when 条件; end loop;
(3)continue [label] [when 表达式]; 如果没有给出label,则continue会跳到最内层的开始处,重新进行判断,以决定是否继续执行循环内的语句。如果指定了label,则跳转到该label所在的循环开始处。如果声明了when,则continue命令只有在表达式为真时才被执行,否则将直接执行continue后面的语句。
(4)[<<label>>] while 表达式 loop 语句 end loop [label];只要条件表达式为真,则其块内的语句就会被循环执行,条件是在每次进入循环时进行判断的。
(5)[<<label>>] for 变量 in [reverse] 表达式..表达式 loop 语句 end loop [label];其中变量自动被定义为integer类型,其作用域仅为for循环的块内。表示范围上下界的两个表达式只在进入循环时计算一次,每次迭代变量值自增1,但是如果声明了reverse,则name变量在每次迭代中将会自动减少1.
(6)[<<label>>] for 行或者记录 in 查询语句 loop 其他语句 end loop [label]; 注意它是另一种形式的for循环,该循环中可以遍历命令的结果并且操作相应的数据。对于遍历结果集,我们也可以把查询语句用 "execute 文本查询语句" 的方式来使用。
第三,异常
在plpgsql中,如果没有捕获到异常,函数会在发生错误时直接退出,与其相关的事务也会被回滚。我们可以使用带有exception子句的begin块来捕获它并且让其恢复,格式如下:
BEGIN
其他语句;
EXCEPTION
when 错误情况 then 处理语句
when 错误情况 then 处理语句
END;
如果没有错误发生时,只有BEGIN块中的语句会被正常执行,一旦这些语句中有任意一条发生错误,其后的语句都将被跳过,直接跳到exception块的开始处。
第四,抛出错误
我们可以在plpgsql中利用raise 语句报告错误信息和抛出错误,格式为:raise level 'format' [,expression [,...]]; 这里包含的级别有DEBUG(向服务器日志写信息)、LOG(向服务器日志写信息,优先级更高)、INFO、NOTICE和WARNING(把信息写到服务器日志以及转发到客户端应用,优先级逐步升高) ,而EXCEPTION则是抛出一个错误,通常是退出当前事务。
某个优先级别的信息是高爆给客户端还是写到服务器日志,还是两个均是,是由log_min_messages和client_min_messages这两个系统初始化参数控制的。
在format部分中,%表示占位符,其实际值仅在RAISE命令执行时由后面的变量替换,如果要在format中使用%自身,应该使用%%的形式。