postgreSQL基本教程-创建函数

  1. 创建标量函数

       在PL/pgSQ中,标量函数是指返回单个标量值(例如整数、浮点数、字符串等)的函数。这意味着标量函数接受参数,并返回单个值作为结果。

      在 PL/pgSQL 中声明标量函数时,需要指定返回类型,该返回类型可以是任何合法的 PostgreSQL 数据类型,例如 integer、text、numeric 等。标量函数可以用于执行诸如计算、转换或逻辑判断等操作,并返回单个结果值。
     

    --创建函数的基本结构
    CREATE OR REPLACE FUNCTION get_user_count() --这个函数是否存在如果不存在就创建,如果存在会提示你
      RETURNS INTEGER                           --自己规定返回值,注意这里是"returns"
      AS $$                                     --$$用于定义多行字符串,也可以写作“$body$”
    DECLARE                                     --declare声明变量
        user_count INTEGER;
    BEGIN                                       --开始
        SELECT COUNT(*) INTO user_count FROM public.users;
        RETURN user_count;                      --return返回值,注意和returns的类型要相同
    END;
    $$ LANGUAGE plpgsql;                        --$$与前面的对应,
                                                --LANGUAGE 指定函数体使用的编程语言为 PL/pgSQL
    
    
  2. 表函数

    1. 什么是表函数? 在 PostgreSQL 中,表函数可以返回一个表格变量,这意味着可以像查询表一样对其进行引用和操作。在下面的示例中,我们创建了一个名为 get_users_by_age 的表函数,它接受一个整数参数 age_threshold,并返回一个包含 nameage 列的表格。函数体中使用 RETURN QUERY 语句执行了一个查询,根据传入的年龄阈值来筛选出符合条件的用户数据。

    2. CREATE FUNCTION get_users_by_age(age_threshold INTEGER)
        RETURNS TABLE (name TEXT, age INTEGER)
        AS $$
        BEGIN
          RETURN QUERY SELECT name, age FROM users WHERE age > age_threshold;
        END;
        $$
        LANGUAGE plpgsql;
      --可以这样调用:
      SELECT * FROM get_users_by_age(30);
      --也可直接按照函数调用:
      SELECT get_users_by_age(30);
      
    3. 表函数的分类:

      1. 内联:

        CREATE OR REPLACE FUNCTION get_all_users()
          RETURNS TABLE (userid INTEGER, username CHARACTER VARYING(20), userpassword CHARACTER VARYING(50))
          AS
          $$
            SELECT userid, username, userpassword FROM public.users;
          $$
          LANGUAGE sql ;
        select get_all_users();
        --或者:
        select * from get_all_users();
        
        • 内联函数通常使用 LANGUAGE sql 来定义,其函数体中包含了单个 SQL 查询语句。
        • 内联函数非常适合简单的查询逻辑,可以将查询直接嵌入到函数体中,提高执行效率。
        • 适用于简单的数据检索、过滤和计算等场景,其优势在于简洁并且执行效率高。
      2. 多语句函数(Multi-Statement Functions):

        • 多语句函数通常使用 LANGUAGE plpgsql 或其他类似的语言来定义,其函数体可以包含多个 SQL 查询语句以及其他逻辑控制语句。

        • 多语句函数适用于需要复杂逻辑处理的场景,例如循环、条件判断、异常处理等。

        • 适用于需要进行更复杂数据转换、业务逻辑处理、数据操作等场景,其优势在于可以编写更复杂的程序逻辑。

        • 下面实现和内联一样的功能,可以对比理解。

          CREATE OR REPLACE FUNCTION get_all_users()
            RETURNS TABLE (userid int, username character varying(20), userpassword character varying(50))
            AS
          $$
          BEGIN
              RETURN QUERY SELECT * FROM public.users;
              
          END;
          $$ LANGUAGE plpgsql;
          
          select * from get_all_users();
          
          
    4. 使用setof类型,要用return next

  3. 存储过程,调用别的函数,捕获处理异常

    • 存储过程是一段预先编译好并存储在数据库中的可重复使用的程序代码。它们允许您在数据库中创建一组 SQL 语句和逻辑操作,然后通过简单地调用该存储过程来执行这些操作。存储过程通常用于封装常见的业务逻辑操作,以便重复使用.

    • 在存储过程中调用其他函数和异常处理,这里尝试调用下面这个除法函数,想要实现的异常处理是,如果出现除数是0那么报错:

      CREATE OR REPLACE FUNCTION test(a0 int)--这里我创建一个除法函数
      returns int as
      $$
      declare a1 int;
      begin a1=a0/(a0-6);
      return a1;
      end
      $$
      language plpgsql;
      

      下面是一个完整的包含查询、调用和捕获异常的存储过程:

      CREATE OR REPLACE PROCEDURE retrieve_user_data(id int)
      AS $$
      DECLARE password text;
      number int;
      BEGIN
          -- 根据用户id查询用户表中的userpassword
          SELECT userpassword into password FROM hello 
      	where userid=id;
      	raise notice'这个id=%的用户密码是%',id,password;
          -- 调用其他函数(这里调用刚刚创建的test函数)
          select test(id) into number;
      	raise notice'a/(a-6)=%',number;
      EXCEPTION
          -- 捕获异常并处理,underfined_table表示欸有这个表;others表示其他异常
          WHEN undefined_table THEN
              RAISE NOTICE '捕获到 undefined_table 异常';
      	WHEN division_by_zero THEN
              RAISE NOTICE '捕获到 division_by_zero 异常';
          WHEN others THEN
              RAISE EXCEPTION '发生了其他异常';
      END;
      $$ LANGUAGE plpgsql;
      
    • 调用语句如下:我把输入值设为6,在查询语句中,发现查询的用户密码是123,在test中出现除数为0的情况,这里报了第二个错误的提示

    • 如果我把查询语句里的表修改成一个不存在的表,那么结果如下,并且我们发现当代码执行到查询错误之后后面的调用test部分没有运行,可以知道检测出错误之后代码直接跳到了异常处理结束执行。

  4. format()用法

    1. 在 PostgreSQL 中,可以使用 format() 函数来格式化字符串。该函数接受一个格式字符串和零个或多个参数,并返回格式化后的字符串。下面是一个示例,演示如何使用 format() 函数:

      -- 示例1:简单的格式化字符串
      SELECT format('Hello, %s!', 'World'); -- 输出:Hello, World!
      
      -- 示例2:带有占位符的格式化字符串
      SELECT format('Name: %s, Age: %s', 'John', 25); -- 输出:Name: John, Age: 25
      
      -- 示例3:使用位置参数的格式化字符串
      SELECT format('Name: %1$s, Age: %2$s', 'John', 25); -- 输出:Name: John, Age: 25
      
      
  5. 异常处理使用errcode 和message

    create or replace procedure proce(choice_func int,tablenam text)
    as 
    $body$
    declare notic text;
    begin if choice_func>0 then 
    execute format('create table if not exists %I (tableid serial,column1 varchar(10))',tablenam);
    elseif choice_func<0 then
    execute format('select * from %I',tablenam) into notic;
    raise notice 'quary result %',notic;
    else raise exception 'please dont enter 0';
    end if;
    end
    $body$
    language plpgsql;
    
    call proce(-1,'newtable1');
    
  6. create table mytab(firstname varchar(20),lastname varchar(20));
    INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones'); 
    create or replace function mma()
    returns int as
    $$
    declare x int:=-1;
    y int;
    BEGIN 
     UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones'; 
     x := x + 1; 
     y := x / 0; 
    EXCEPTION 
     WHEN division_by_zero THEN RAISE NOTICE 'перехватили ошибку division_by_zero'; 
     RETURN x; 
    return x;
    END; 
    $$
    language plpgsql;
    
    select mma();
    select * from mytab;
    
  7. 递归查询

    create table depart(
    	departid serial primary key not null,
    	sub_departid int
    );
    insert into depart(sub_departid) values(7),(6),(1),(2),(4),(3),(5);
    select * from depart;
    
    with recursive t as 
    (
    	select departid,sub_departid from public."depart" where departid=1
    	union 
    	select d.departid,d.sub_departid from public."depart" d,t where d.sub_departid=t.departid
    )select * from t;

  8. 关于游标的使用

    create or replace function cur_try()
    returns text as
    $$
    declare cur1 refcursor;
    r record;
    
    begin 
    open cur1 for select * from files;
    fetch cur1 into r;
    raise notice 'cur1.filename:%',r.filename;
    close cur1;
    return r.fileid;
    end
    $$
    language plpgsql;
    
    select cur_try();

    推荐下面这个关于游标使用的教程,很详细:Postgresql游标使用介绍(cursor)_postgresql 游标-CSDN博客

一些内置函数和磁盘函数,结构体类型数据使用:

create type person as(person_name text,age int);
create or replace function try_inner_function(person_info person)
returns text as
$$
declare str text:=person_info.person_name||' is '||person_info.age::text||' years old';
strlen int;
strbig bigint;
begin strlen=char_length(str);
raise notice 'strlen is %',strlen;
strbig=pg_column_size(str);
raise notice 'strbit is %',strbig;
return str;
end
$$
language plpgsql;

select try_inner_function(row('Anna',23));

  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值