zoukankan      html  css  js  c++  java
  • pgsql 的函数

    因为pgsql中没有存储过程和包,所以类似功能通过函数来实现

    PostgreSQL的存储过程简单入门 http://blog.csdn.net/rachel_luo/article/details/8073458 
    存储过程事物 http://www.php100.com/manual/PostgreSQL8/tutorial-transactions.html 
    PL/pgSQL - SQL存储过程语言 https://wiki.postgresql.org/wiki/9.1%E7%AC%AC%E4%B8%89%E5%8D%81%E4%B9%9D%E7%AB%A0

    postgreSQL存储过程写法示例http://blog.sina.com.cn/s/blog_448574810101f64u.html 
    结构 
    PL/pgSQL是一种块结构的语言,比较方便的是用pgAdmin III新建Function,填入一些参数就可以了。基本上是这样的: 

    Sql代码  收藏代码
    1. CREATE OR REPLACE FUNCTION 函数名(参数1,[整型 int4, 整型数组 _int4, ...])  
    2. RETURNS 返回值类型 AS  
    3. $BODY$  
    4. DECLARE  
    5. 变量声明  
    6. BEGIN  
    7. 函数体  
    8. END;  
    9. $BODY$  
    10. LANGUAGE ‘plpgsql’ VOLATILE;  


    变量类型 
    除了postgresql内置的变量类型外,常用的还有 RECORD ,表示一条记录。 
    赋值 
    赋值和Pascal有点像:“变量 := 表达式;” 
    有些奇怪的是连接字符串的是“||”,比如 sql := ‘SELECT * FROM’ || table || ‘WHERE …’; 
    判断 
    判断又和VB有些像: 
    IF 条件 THEN 
    … 
    ELSEIF 条件 THEN 
    … 
    ELSE 
    … 
    END IF; 
    循环 
    循环有好几种写法: 
    WHILE expression LOOP 
    statements 
    END LOOP; 
    还有常用的一种是:(从1循环到9可以写成FOR i IN 1..9 LOOP) 
    FOR name IN [ REVERSE ] expression .. expression LOOP 
    statements 
    END LOOP; 
    其他 
    还有几个常用的函数: 
    SELECT INTO record …; 表示将select的结果赋给record变量(RECORD类型) 
    PERFORM query; 表示执行query并丢弃结果 
    EXECUTE sql; 表示执行sql语句,这条可以动态执行sql语句(特别是由参数传入构造sql语句的时候特别有用) 

    参数: 
    传递给函数的参数都是用 $1,$2,等等这样的标识符。有时候为了增强可读性,我们可以为 $n 参数名声明别名。然后通过这个别名或者数字标识符可以指向这个参数值。 
    有两种方法创建一个别名。最好的方法是用CREATE FUNCTION命令给予这个参数一个名字,例如: 

    Sql代码  收藏代码
    1. CREATE FUNCTION sales_tax(subtotal real) RETURNS real AS $$  
    2. BEGIN  
    3.    RETURN subtotal * 0.06;  
    4. END;  
    5. $$ LANGUAGE plpgsql;  


    另一个方法是,在PostgreSQL 8.0之前唯一的方法,明确的用别名进行声明,用以下的语法进行声明: 
       name ALIAS FOR $n; 
    这个风格的同一个例子看起来像下面这样 : 

    Sql代码  收藏代码
    1. CREATE FUNCTION sales_tax(real) RETURNS real AS $$  
    2. DECLARE  
    3.     subtotal ALIAS FOR $1;  
    4. BEGIN  
    5.     RETURN subtotal * 0.06;  
    6. END;  
    7. $$ LANGUAGE plpgsql;  


    注意:这两个例子不是完全一样的。在第一种情况,subtotal可以用sales_tax.subtotal进行引用,但是在第二种情况下不能这么做。(如果我们给这个内部块附加了一个标签,subtotal能够替代这个标签) 
    一些更多的例子: 

    Sql代码  收藏代码
    1. CREATE FUNCTION instr(varchar, integer) RETURNS integer AS $$  
    2. DECLARE  
    3.      v_string ALIAS FOR $1;  
    4.      index ALIAS FOR $2;  
    5. BEGIN  
    6.       -- some computations using v_string and index here  
    7. END;  
    8. $$ LANGUAGE plpgsql;  
    9.   
    10. CREATE FUNCTION concat_selected_fields(in_t sometablename) RETURNS text AS $$  
    11. BEGIN  
    12.      RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;  
    13. END;  
    14. $$ LANGUAGE plpgsql  


    当一个PL/pgSQL函数用输出参数来进行声明时,给予这个输出参数$n名和一个任意的别名跟正常输入参数是同样的方法。即使这个输出参数以NULL开始时也是一个有效的变量,它应该在函数的执行过程中被分配。这个参数最好的值将被返回。例如,这个sales-tax例子也可以用这种方法完成: 

    Sql代码  收藏代码
    1. CREATE FUNCTION sales_tax(subtotal real, OUT tax real) AS $$  
    2. BEGIN  
    3.      tax := subtotal * 0.06;  
    4. END;  
    5. $$ LANGUAGE plpgsql;  


    注意:我们省略了RETURNS real---我们可以将它包括在内,但它是多余的。 
    当返回多个值的时候输出参数将非常有用,一个简单的例子是: 

    Sql代码  收藏代码
    1. CREATE FUNCTION sum_n_product(x int, y int, OUT sum int, OUT prod int) AS $$  
    2. BEGIN  
    3.     sum := x + y;  
    4.     prod := x * y;  
    5. END;  
    6. $$ LANGUAGE plpgsql;  


    如在Section 35.4.4中的讨论,这将为这个函数的结果创建一个匿名的记录类型。如果使用了RETURNS字句,那么必须给它指明RETURNS记录。 
    另外一种方法声明PL/pgSQL函数是用RETURNS TABLE,例如: 

    Sql代码  收藏代码
    1. CREATE FUNCTION extended_sales(p_itemno int)  
    2. RETURNS TABLE(quantity int, total numeric) AS $$  
    3. BEGIN  
    4.      RETURN QUERY SELECT quantity, quantity * price FROM sales  
    5.              WHERE itemno = p_itemno;  
    6. END;  
    7. $$ LANGUAGE plpgsql;  


    这跟声明一个或者多个OUT参数和制定RETURNS SETOF这些类型是同样的方法。 
    当返回的PL/pgSQL函数的类型被声明为一个多态类型(anyelement, anyarray, anynonarray, 或者anyenum),特殊参数$0将被创建。它的数据类型将实际的返回函数的类型,从实际的输入类型返回(见Section 35.2.5)。这运行这个函数访问这个实际的返回类型如Section 39.3.3显示的那样。$0初始值为空并且能够被函数修改,如果需要,它可以用于保留返回值,虽然这不是必须的。$0也可以被给予一个别名。例如,这个函数能在任意一个有+操作符的数据类型上工作: 

    Sql代码  收藏代码
    1. CREATE FUNCTION add_three_values(v1 anyelement, v2 anyelement, v3 anyelement)  
    2. RETURNS anyelement AS $$  
    3. DECLARE  
    4.     result ALIAS FOR $0;  
    5. BEGIN  
    6.     result := v1 + v2 + v3;  
    7.     RETURN result;  
    8. END;  
    9. $$ LANGUAGE plpgsql  


    声明一个或者多个多态类型的输出参数也是同样的效果。这种情况下这个特殊的$0参数将不会被用到,这个输出参数本身也是同样的作用,例如: 

    Sql代码  收藏代码
    1. CREATE FUNCTION add_three_values(v1 anyelement, v2 anyelement, v3 anyelement,  
    2.                              OUT sum anyelement)  
    3. AS $$  
    4. BEGIN  
    5.     sum := v1 + v2 + v3;  
    6. END;  
    7. $$ LANGUAGE plpgsql;  



    39.3.2. 别名 
       newname ALIAS FOR oldname; 
    这个ALIAS语法比以前的章节中介绍的更加普通:你可以为任意一个变量声明一个别名,不只是函数的参数。这实际的用途是用预定义的名字为变量定义不同的名字,如触发器过程中的NEW或者OLD。 例子: 

    Sql代码  收藏代码
    1. DECLARE  
    2.    prior ALIAS FOR old;  
    3.    updated ALIAS FOR new;  


    因此,ALIAS使同样的对象有两种不同的方式命名,如果不限制的使用,将会变得混乱。这种方法最好只用于覆盖预定义的名字。 



    最后,贴出解决上面这个问题的存储过程吧: 

    Sql代码  收藏代码
    1. CREATE OR REPLACE FUNCTION message_deletes(ids "varchar", userid int8)  
    2.   RETURNS int4 AS  
    3. $BODY$  
    4. DECLARE  
    5.   r RECORD;  
    6.   del bool;  
    7.   num int4 := 0;  
    8.   sql "varchar";  
    9. BEGIN  
    10.   sql := 'select id,receiveuserid,senduserid,senddelete,receivedelete from message where id in (' || ids || ')';  
    11.   FOR r IN EXECUTE sql LOOP  
    12.     del := false;  
    13.     IF r.receiveuserid=userid and r.senduserid=userid THEN  
    14.       del := true;  
    15.     ELSEIF r.receiveuserid=userid THEN  
    16.       IF r.senddelete=false THEN  
    17.         update message set receivedelete=true where id = r.id;  
    18.       ELSE  
    19.         del := true;  
    20.       END IF;  
    21.     ELSEIF r.senduserid=userid THEN  
    22.       IF r.receivedelete=false THEN  
    23.         update message set senddelete=true where id = r.id;  
    24.       ELSE  
    25.         del := true;  
    26.       END IF;  
    27.     END IF;  
    28.     IF del THEN  
    29.       delete from message where id = r.id;  
    30.       num := num + 1;  
    31.     END IF;  
    32.   END LOOP;  
    33.   return num;  
    34. END;  
    35. $BODY$  
    36.   LANGUAGE 'plpgsql' VOLATILE;  





    下面的例子是要调用一个存储过程自动创建对应的一系列表: 

    Sql代码  收藏代码
    1. CREATE OR REPLACE FUNCTION create_table_for_client(id int)  
    2. RETURNS integer AS  
    3. $BODY$  
    4. DECLARE  
    5. num int4 := 0;  
    6. sql "varchar";  
    7. BEGIN  
    8. sql := 'create table _' || id || '_company(id int, name text)';  
    9. EXECUTE sql;  
    10. sql := 'create table _' || id || '_employee(id int, name text)';EXECUTE sql;  
    11. sql := 'create table _' || id || '_sale_bill(id int, name text)';EXECUTE sql;  
    12. .......  
    13. return num;  
    14. END;  
    15. $BODY$ LANGUAGE plpgsql VOLATILE  




    自动创建序列 
    第一个例子

    Sql代码  收藏代码
    1. CREATE OR REPLACE FUNCTION auto_gen_seq() RETURNS bigint AS  
    2. $BODY$  
    3. DECLARE   
    4. rd RECORD;  
    5. num int4 := 0;  
    6. sql "varchar";    
    7. seq_sql varchar;  
    8. BEGIN      
    9.   sql := 'SELECT tablename FROM pg_tables WHERE tablename NOT LIKE ''pg%'' AND tablename NOT LIKE ''sql_%'' ORDER BY tablename;';    
    10.   FOR rd IN EXECUTE sql LOOP    
    11.     seq_sql:='CREATE SEQUENCE SQ_'||rd.tablename||' START 1000000 CACHE 30;';       
    12.       BEGIN  
    13.         EXECUTE seq_sql;    
    14.         EXCEPTION  
    15.           WHEN TOO_MANY_ROWS THEN  
    16.              RAISE EXCEPTION 'employee % not unique', seq_sql;  
    17.           WHEN OTHERS THEN  
    18.              return -1;  
    19.       END;  
    20.     num := num + 1;      
    21.   END LOOP;      
    22.   return num;      
    23. END;  
    24. $BODY$  
    25. LANGUAGE plpgsql VOLATILE NOT LEAKPROOF  
    26. COST 100;  


    调用: 

    Sql代码  收藏代码
    1. select auto_gen_seq()  



    第二个例子 

    Sql代码  收藏代码
    1. -- Function: auto_gen_seq(character)  
    2.   
    3. -- DROP FUNCTION auto_gen_seq(character);  
    4.   
    5. CREATE OR REPLACE FUNCTION auto_gen_seq("tbName" character)  
    6.   RETURNS character varying AS  
    7. $BODY$/*  
    8.     调用示例:  
    9.   
    10. SELECT tablename as tableName,   
    11. 'sq_'||REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(tablename, 'tb_am_', ''), 'tb_sm_', ''), 'tb_pm_', ''), 'tb_pc_', ''), 'tb_ps_', ''), 'rh_', ''), 'TB_', ''), 'RH_', '' ), 'tb_', '') AS sqName  
    12. ,auto_gen_seq(tablename||'') as successFlag,current_date,current_time FROM pg_tables WHERE tablename NOT LIKE 'pg%' AND tablename NOT LIKE 'sql_%' ORDER BY successFlag,tablename;  
    13.   
    14. */  
    15.   
    16. DECLARE    
    17. rd RECORD;    
    18. seq_sql varchar;    
    19. flag_str varchar;  
    20. sq_name varchar;  
    21. sq_datetime varchar;  
    22. BEGIN  
    23.   
    24.   seq_sql:='create table _sequence_table ( id SERIAL not null, code VARCHAR(200) null, increment_num INT8 null, minvalue_num INT8 null, maxvalue_num INT8 null, start_num INT8 null, cache_num INT8 null, cycle_flag VARCHAR(100) null,create_datetime timestamp without time zone,constraint PK__SEQUENCE_TABLE primary key (id) );CREATE UNIQUE INDEX INDEX__sequence_table ON _sequence_table (code);';  
    25.       BEGIN    
    26.          EXECUTE seq_sql;      
    27.          EXCEPTION    
    28.             WHEN OTHERS THEN    
    29.                 flag_str:='失败';    
    30.       END;  
    31.   
    32.   --sq_name:=replace(replace($1, 'TB_', ''), 'RH_', '');  
    33.   --sq_name:=replace(replace(sq_name, 'tb_', ''), 'rh_', '');  
    34.   sq_name:='sq_'||REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE($1, 'tb_am_', ''), 'tb_sm_', ''), 'tb_pm_', ''), 'tb_pc_', ''), 'tb_ps_', ''), 'rh_', ''), 'TB_', ''), 'RH_', '' ), 'tb_', '');  
    35.   /*  
    36.   seq_sql:='drop SEQUENCE '||sq_name||';';         
    37.     BEGIN    
    38.       EXECUTE seq_sql;      
    39.       EXCEPTION    
    40.          WHEN OTHERS THEN    
    41.              flag_str:='失败';    
    42.       END;   
    43.   */    
    44.   seq_sql:='CREATE SEQUENCE '||sq_name||' START 1000000 CACHE 30;';         
    45.     BEGIN    
    46.       EXECUTE seq_sql;      
    47.       EXCEPTION    
    48.          WHEN OTHERS THEN    
    49.              return '失败,创建序列';    
    50.       END;     
    51.   
    52.   sq_datetime:=to_timestamp(current_date||' '||current_time,'yyyy-mm-dd hh24:mi:ss') ;  
    53.   seq_sql:='INSERT INTO _sequence_table( code,increment_num,minvalue_num,start_num, cache_num,create_datetime) VALUES ( '''||sq_name||''',1,1000000,1000000, 30,'''||sq_datetime||''');';         
    54.     BEGIN    
    55.       EXECUTE seq_sql;      
    56.       EXCEPTION    
    57.          WHEN OTHERS THEN    
    58.              return '失败,插入序列信息';    
    59.       END;   
    60.         
    61.   return '成功';        
    62. END;  
    63. $BODY$  
    64.   LANGUAGE plpgsql VOLATILE STRICT  
    65.   COST 100;  
    66. ALTER FUNCTION auto_gen_seq(character)  
    67.   OWNER TO postgres;  


    调用 

    Sql代码  收藏代码
      1. SELECT tablename as tableName,   
      2. 'sq_'||REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(tablename, 'tb_am_', ''), 'tb_sm_', ''), 'tb_pm_', ''), 'tb_pc_', ''), 'tb_ps_', ''), 'rh_', ''), 'TB_', ''), 'RH_', '' ), 'tb_', '') AS sqName  
      3. ,auto_gen_seq(tablename||'') as successFlag,current_date,current_time FROM pg_tables WHERE tablename NOT LIKE 'pg%' AND tablename NOT LIKE 'sql_%' ORDER BY successFlag,tablename;  

    转载自:https://www.iteye.com/blog/panyongzheng-2194815

  • 相关阅读:
    git命令上传项目到码云总结
    根据数组对象的某个属性值找到指定的元素
    Web前端开发规范文档
    在vue项目中安装使用Mint-UI
    字蛛fontSpider的使用
    vue 组件之间的数据传递
    ElasticStack系列之十 & 生产中的问题与解决方案
    ElasticStack系列之九 & master、data 和 client 节点
    ElasticStack系列之八 & _source 字段
    ElasticStack系列之七 & IK自动热更新原理与实现
  • 原文地址:https://www.cnblogs.com/zhangruiyuan/p/11416657.html
Copyright © 2011-2022 走看看