热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

postgreSQL存储过程写法示例

转载自:http:panyongzheng.iteye.comblog2194815PostgreSQL的存储过程简单入门http:blog.csdn.netrac

转载自:http://panyongzheng.iteye.com/blog/2194815

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 realRETURNS 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(realRETURNS 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(varcharintegerRETURNS 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 realOUT tax realAS $$  
  2. BEGIN  
  3.      tax := subtotal * 0.06;  
  4. END;  
  5. $$ LANGUAGE plpgsql;  




注意:我们省略了RETURNS real---我们可以将它包括在内,但它是多余的。 


当返回多个值的时候输出参数将非常有用,一个简单的例子是: 


Sql代码  收藏代码
  1. CREATE FUNCTION sum_n_product(x int, y intOUT sum intOUT prod intAS $$  
  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 numericAS $$  
  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;  


推荐阅读
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • PDO MySQL
    PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
author-avatar
男孩形式恋人
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有