PL/pgSQL编写postgresql函数(三)--流程控制

目录

 

流程控制结构

1.函数里结果返回

1.1 RETURN

1.2 RETURN NEXT及RETURN QUERY

2.条件控制

2.1 IF 语法

IF ... THEN ... END IF

IF ... THEN ... ELSE ... END IF

IF ... THEN ... ELSEIF ... THEN ... ELSE ... END IF

注意:这个语法可以有多个elseif

2.2 CASE 语法

CASE ... WHEN ... THEN ... ELSE ... END CASE

注意:

CASE WHEN ... THEN ... ELSE ... END CASE

3. 循环遍历

3.1 LOOP与EXIT

3.2 LOOP 与CONTINUE

3.3 WHILE与LOOP

3.4 FOR与LOOP

用法一:整数范围迭代

用法二:查询结果迭代

3.5 FOREACH与LOOP

无slice或者slice 0

有slice且slice不为0

如果将slice的number值设置为2


流程控制结构

1.函数里结果返回

两个命令让我们可以从函数中返回数据:return 和 return next。

1.1 RETURN

语法:RETURN expression;

表达式RETURN用于终止函数并把expression的值返回给调用者。这种形式用于不返回集合数据(数据集)的PL/pgSQL函数。

用法详解

(1)如果函数返回一个标量类型,表达式结果将自动转行成函数的返回类型。但要返回一个复合(行)值,必须写一个所需列集合的表达式。

标量示例

create or replace function fn_scalar() returns numeric as 

$$

declare

begin

return (3+4*2)-(2*2-1);

end 

$$

language plpgsql

复合示例

create or replace function fn_scalars() returns record as 

$$

declare

begin

return (1,2,'three'::text);

end 

$$

language plpgsql   

 

select * from fn_scalars() as (first int, second int,third text); 

--函数中使用record类型来接受,调用时需要构造正确类型。或者函数中构造正确类型返回,然后直接select * from 调用。

(2)如果声明带输出参数的函数,只需要写不带表达式的RETURN,输出参数变量的当前值被返回

create or replace function fn_out_return(out rcd text) returns text as 

$$

declare

begin

select name into rcd from t_test where id =3;

        return ;   --有out参数这个return也可以省略。

end 

$$

language plpgsql

(3)如果声明函数返回void,RETURN可以用来提前结果函数,但函数最后不要写RETURN

create or replace function fn_void_return() returns void as 

$$

begin

raise notice '执行第一行';

raise notice '执行第二行';

return;

raise notice '执行第三行';

end 

$$

language plpgsql

调用函数:可以看到执行完第二行函数直接return返回结束了。

1.2 RETURN NEXT及RETURN QUERY

语法: RETURN NEXT expression;

RETURN QUERY  query;

RETURN QUERY EXECUTE command-string [ USING expression [,...]];

当函数被声明为返回returns setof sometype,规则和直接return sometype有所不同。这种情况下,返回的个体项被RETURN NEXT或者RETURN QUERY 命令序列指定,并接着会用一个不带参数的RETURN命令来指示这个函数已经完成执行。

(1)RETURN NEXT可以返回标量和复合类型,对于复合类型,将返回一个完整的结果“表”(结果集)。

create or replace function fn_return_nexts() returns setof t_test as

$$

declare

r t_test%rowtype;

begin

for r in select * from t_test

loop

--这里可以对每一行数据进行操作

raise notice 'user_name=%',r.name;

return next r;  --返回SELECT的当前行

end loop;

return; --表明函数执行完毕

end 

$$

language plpgsql

(2)RETURN QUERY 将执行一个查询的结果追加到一个函数结果中。

create or replace function fn_return_query() returns setof t_test as

$$

declare

r record;

begin

return query(select * from t_test);

end 

$$

language plpgsql

RETURN NEXT和RETURN QUERY实际上不会从函数返回:它简单地想函数结果集中追加零或多行,然后继续执行下一条语句,以此建立一个结果集,最后一个RETURN(无参数)控制退出函数。

(3)RETURN QUERY EXECUTE是RETURN QUERY的一个变体,主要用来执行动态查询。可以通过USING想计算出的查询字符串中插入参数表达式,这与在EXECUTE中使用方法一致。

参考的例子,我们往子表t_user_12中多添加几行数据

insert into t_user(name,age,code) values('赵六',20,'12011-11');

insert into t_user(name,age,code) values('刘七',21,'12012-11');

 

create or replace function fn_query_execute(partition_code varchar)

returns setof t_user as 

$$

    declare

var_sql text;

    begin

    var_sql := 'select *  from t_user_'||partition_code||';';

    raise notice '====%',var_sql;

return query EXECUTE var_sql;

    end 

$$

language plpgsql

调用函数:

2.条件控制

目前plpgsql支持三种IF条件控制语法:

IF ... THEN ... END IF

IF ... THEN ... ELSE ... END IF

IF ... THEN ... ELSEIF ... THEN ... ELSE ... END IF

以及两种CASE语法:

CASE ... WHEN ... THEN ... ELSE ... END CASE

CASE WHEN ... THEN ... ELSE ... END

2.1 IF 语法

IF ... THEN ... END IF

例子

create or replace function fn_if_then(uid boolean) returns text as

$$

declare

v_value text  default '参数值不为TRUE';

begin

if uid = true then

v_value='参数值为TRUE';

end if;

return v_value;

end 

$$

language plpgsql

调用函数

IF ... THEN ... ELSE ... END IF

例子

create or replace function fn_if_else(uid int) returns text as

$$

declare

v_value text;

begin

if uid = 1 then

v_value='参数值为1';

else

v_value='参数值不为1';

end if;

return v_value;

end 

$$

language plpgsql

调用函数

IF ... THEN ... ELSEIF ... THEN ... ELSE ... END IF

例子:

create or replace function fn_if_elseif(uid int) returns text as

$$

declare

v_value text;

begin

if uid = 1 then

v_value='参数值为1';

elseif uid=2 then

v_value='参数值为2';

else

v_value='参数值即不为1也不为2';

end if;

return v_value;

end 

$$

language plpgsql

调用函数

 

注意:这个语法可以有多个elseif

例子

create or replace function fn_if_elseifs(uid int) returns text as

$$

declare

v_value text;

begin

if uid = 1 then

v_value='参数值为1';

elseif uid=2 then

v_value='参数值为2';

elseif uid=3 then

v_value='参数值为3';

elseif uid=4 then

v_value='参数值为4';

else

v_value='其他情况';

end if;

return v_value;

end 

$$

language plpgsql

调用函数

2.2 CASE 语法

CASE ... WHEN ... THEN ... ELSE ... END CASE

例子

create or replace function fn_case_col_when(uid int) returns text as

$$

declare

v_value text;

begin

case uid when 1 then

v_value = 'uid值为'||uid;

when 2 then

v_value = 'uid值为'||uid;

else 

v_value = 'uid值不为1也不为2';

end case;

return v_value; 

end 

$$

language plpgsql

调用函数

 

注意:

该语法中when ... then ... 是可以有多个的。上面 IF ... THEN ... ELSEIF ... THEN ... ELSE ... END IF语法中elseif也可以是多个的,但是elseif后不需要else 直接跟end if结果判断不出错,而该语法中when ... then 后面不跟else,创建函数时不会报错,但调用时,如果没有值符合when 中的值时,调用会报错。

如:错误示例

create or replace function fn_case_col_when_erro(uid int) returns text as

$$

declare

v_value text;

begin

case uid when 1 then

v_value = 'uid值为'||uid;

when 2 then

v_value = 'uid值为'||uid;

end case;  --缺少else直接end case

return v_value; 

end 

$$

language plpgsql

调用函数

如上,满足函数里判断条件时,不报错,不满足时,报错。

CASE WHEN ... THEN ... ELSE ... END CASE

该case属于搜索case,when 后面可以赋予不同的参数布尔表达式(= 号左、右边的参数均可变)

例子

create or replace function fn_casewhen_expression(uid int,uname varchar) returns text as

$$

declare

v_value text;

begin

case when uid = 1 then

v_value = 'UID或UNAME满足条件';

when uname = '张三' then

v_value = 'UID或UNAME满足条件';

else 

v_value = 'UID和UNAME都不满足条件';

end case;    

return v_value; 

end 

$$

language plpgsql

调用函数

 

如上,函数逻辑是只要uid = 1 或者uname = ‘张三’ ,v_value的返回值就为 “UID或UNAME满足条件”

但第一种case: CASE ... WHEN ... THEN ... ELSE ... END CASE 只能判断“=”号右边的值,等号左边的参数是固定的。

如果else不存在,照样会抛出异常:ERROR:  20000: case not found

提示:  CASE statement is missing ELSE part.

3. 循环遍历

PL/pgSQLL中通过Loop、EXIT、CONTINUE、WHILE、FOR和FOREACH语句,可以安排PL/pgSQL重复执行一系列命令。

注意:LOOP  ...  END LOOP 语法避免单独使用,单独使用是死循环,一定要有跳出循环的语句(exit 或者直接return结束函数)

3.1 LOOP与EXIT

语法

(1)LOOP

         -- 一些计算

       IF count > 0 THEN

        EXIT;  -- 退出循环

        END IF;

END LOOP;

 

(2)LOOP

         -- 一些计算

       EXIT when count > 0;  -- 退出循环

        

END LOOP;

 

例子1

create or replace function fn_loop_exit() returns text as 

$$

declare

v_value int default 0;

v_result text;

begin

loop

v_value = v_value + 1;

raise notice 'LOOP循环%次',v_value;

if v_value > 5 then

v_result = '退出循环v_value='||v_value;

EXIT;  --退出循环

end if;

end loop;

   return v_result;

end 

$$

language plpgsql

调用函数

例子2:例子中的if可以直接改写成 EXIT when expression

create or replace function fn_loop_exit() returns text as 

$$

declare

v_value int default 0;

v_result text;

begin

loop

v_value = v_value + 1;

raise notice 'LOOP循环%次',v_value;

 

EXIT when v_value > 5;  --退出循环

 

end loop;

   return  '退出循环v_value='||v_value;

end 

$$

language plpgsql

调用函数

3.2 LOOP 与CONTINUE

语法

LOOP

    -- 一些计算

    EXIT WHEN boolean-expression1;

    CONTINUE WHEN boolean-expression2;

   -- 一些操作

END LOOP;

 

当boolean-expression2为真时,continue生效,会使得结束本次循环直接跳到下次循环(一些操作 将不会执行)。当boolean-expression2为假时,continue无效,则其后面的一些操作会执行。

如:

LOOP

    -- 一些计算

    EXIT WHEN count > 100;

    CONTINUE WHEN count < 50;

    -- 一些操作 

END LOOP;

当count IN [50 .. 100] 的时候,一些操作会执行。

 

例子

create or replace function fn_loop_continue() returns void as 

$$

declare 

v_value int default 0;

begin

loop

v_value = v_value + 1;

exit when v_value > 5;

continue when v_value < 3;

raise notice 'continue后循环第%次',v_value;

end loop;

end 

$$

language plpgsql

 调用函数

如上,当v_value in [3,5]时,raise notice执行。

3.3 WHILE与LOOP

语法

[ <<label>> ]

WHILE boolean-expression LOOP

    statements

END LOOP [ label ];

 

每次进入循环体之前检查一遍表达式,只要boolean-expression表达式为真,就会进入一次循环体。

   例子

create or replace function fn_loop_while() returns void as 

$$

declare 

v_value int default 0;

begin

raise notice 'while循环开始=======';

while v_value < 6 loop

v_value = v_value + 1;

raise notice '循环第%次',v_value;

end loop;

raise notice 'while循环结束=======';

end 

$$

language plpgsql

调用函数

如上:当v_value in[1,5]时,都会进入循环体执行相关操作,当v_value = 5时进入循环体,此时v_value本次循环后为v_value=6,再次进入循环体时检查v_value<6为false,则结束循环。

3.4 FOR与LOOP

用法一:整数范围迭代

语法

[ <<label>> ]

FOR name IN [ REVERSE ] beginval .. endval [ BY expression ] LOOP

    statements

END LOOP [ label ];

 

    name  变量会自动定义为integer并在循环内存在

beginval  循环开始name的值

endval  结束循环name的值

BY       没有指定,步长为1,指定了则步长为指定值。

REVERSE  省略则beginval到endval为增加(每次增加步长值),指定则beginval到endval为减除(每次减除步长值)

 

例子

create or replace function fn_loop_forint() returns void as

$$

begin

raise notice '第一个for循环开始====';

for i in 1..5 loop

raise notice 'i的值为:%',i;

end loop;

 

raise notice '第二个for循环开始====';

for i in 1..5  by 2 loop

raise notice 'i的值为:%',i;

end loop;

 

raise notice '第三个for循环开始====';

for i in reverse 5..1  by 2 loop

raise notice 'i的值为:%',i;

end loop;

end; 

$$

language plpgsql

 

调用函数

用法二:查询结果迭代

语法

静态

[ <<label>> ]

FOR target IN query LOOP

    statements

END LOOP [ label ];

 

动态

[ <<label>> ]

FOR target IN EXECUTE text_expression [USING expression[,...]] LOOP

    statements

END LOOP [ label ];

 

 

query  是一条查询语句,它会返回一个查询结果集

target   是一个记录变量、行变量或者逗号分隔的标量变量列表,需要事先定义。

EXECUTE 表示动态执行命令

在此循环中,每循环一次,target被赋予来自query的一行,

例子

create or replace function fn_loop_query() returns void as 

$$

declare

v_value record;

count int default 0;

begin

raise notice '循环开始========';

for v_value in select * from t_test loop

count = count + 1;

raise notice '第%次循环,name值为:%',count,v_value.name;

raise notice '第%次循环,age值为:%',count,v_value.age;

raise notice '第%次循环,code值为:%',count,v_value.code;

end loop;

end 

$$

language plpgsql

 

调用函数

使用此FOR语法与return next连用可以用来函数返回数据集。如例子2.3中方式一方式二

3.5 FOREACH与LOOP

FOREACH与FOR循环很像,区别在于FOR是通过SQL返回行进行迭代,而FOREACH是通过一个数组值得元素来迭代。

语法

[ <<label>> ]

FOREACH target [ SLICE number ] IN ARRAY expression LOOP

    statements

END LOOP [ label ];

 

target   变量

SLICE    当省略或者number为0时,遍历数组个体元素。当number为一个不大于数组维度的整数时,FOREACH会通过number的值来对数组进行切片(如number为1,则将数组切成多个维度为一的数组,当numeric为2时则将数组切成多个维度为2的数组)。

例子

无slice或者slice 0

create or replace function fn_foreach(int[]) returns void as 

$$

declare

x int;

begin

foreach x slice 0 in array $1

loop

raise notice '输出value = %',x;

end loop;

end 

$$

language plpgsql;

有slice且slice不为0

create or replace function fn_foreach_slice(int[]) returns void as 

$$

declare

x int[];

begin

foreach x slice 1 in array $1

loop

raise notice '输出row = %',x;

end loop;

end 

$$

language plpgsql

调用函数

如果将slice的number值设置为2

create or replace function fn_foreach_slice_number(int[]) returns void as 

$$

declare

x int[];

begin

foreach x slice 2 in array $1

loop

raise notice '输出row = %',x;

end loop;

end 

$$

language plpgsql

对比结果

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Darion@pg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值