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,填入一些参数就可以了。基本上是这样的:
- CREATE OR REPLACE FUNCTION 函数名(参数1,[整型 int4, 整型数组 _int4, ...])
- RETURNS 返回值类型 AS
- $BODY$
- DECLARE
- 变量声明
- BEGIN
- 函数体
- END;
- $BODY$
- 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命令给予这个参数一个名字,例如:
- CREATE FUNCTION sales_tax(subtotal real) RETURNS real AS $$
- BEGIN
- RETURN subtotal * 0.06;
- END;
- $$ LANGUAGE plpgsql;
另一个方法是,在PostgreSQL 8.0之前唯一的方法,明确的用别名进行声明,用以下的语法进行声明:
name ALIAS FOR $n;
这个风格的同一个例子看起来像下面这样 :
- CREATE FUNCTION sales_tax(real) RETURNS real AS $$
- DECLARE
- subtotal ALIAS FOR $1;
- BEGIN
- RETURN subtotal * 0.06;
- END;
- $$ LANGUAGE plpgsql;
注意:这两个例子不是完全一样的。在第一种情况,subtotal可以用sales_tax.subtotal进行引用,但是在第二种情况下不能这么做。(如果我们给这个内部块附加了一个标签,subtotal能够替代这个标签)
一些更多的例子:
- CREATE FUNCTION instr(varchar, integer) RETURNS integer AS $$
- DECLARE
- v_string ALIAS FOR $1;
- index ALIAS FOR $2;
- BEGIN
- -- some computations using v_string and index here
- END;
- $$ LANGUAGE plpgsql;
- CREATE FUNCTION concat_selected_fields(in_t sometablename) RETURNS text AS $$
- BEGIN
- RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;
- END;
- $$ LANGUAGE plpgsql
当一个PL/pgSQL函数用输出参数来进行声明时,给予这个输出参数$n名和一个任意的别名跟正常输入参数是同样的方法。即使这个输出参数以NULL开始时也是一个有效的变量,它应该在函数的执行过程中被分配。这个参数最好的值将被返回。例如,这个sales-tax例子也可以用这种方法完成:
- CREATE FUNCTION sales_tax(subtotal real, OUT tax real) AS $$
- BEGIN
- tax := subtotal * 0.06;
- END;
- $$ LANGUAGE plpgsql;
注意:我们省略了RETURNS real---我们可以将它包括在内,但它是多余的。
当返回多个值的时候输出参数将非常有用,一个简单的例子是:
- CREATE FUNCTION sum_n_product(x int, y int, OUT sum int, OUT prod int) AS $$
- BEGIN
- sum := x + y;
- prod := x * y;
- END;
- $$ LANGUAGE plpgsql;
如在Section 35.4.4中的讨论,这将为这个函数的结果创建一个匿名的记录类型。如果使用了RETURNS字句,那么必须给它指明RETURNS记录。
另外一种方法声明PL/pgSQL函数是用RETURNS TABLE,例如:
- CREATE FUNCTION extended_sales(p_itemno int)
- RETURNS TABLE(quantity int, total numeric) AS $$
- BEGIN
- RETURN QUERY SELECT quantity, quantity * price FROM sales
- WHERE itemno = p_itemno;
- END;
- $$ LANGUAGE plpgsql;
这跟声明一个或者多个OUT参数和制定RETURNS SETOF这些类型是同样的方法。
当返回的PL/pgSQL函数的类型被声明为一个多态类型(anyelement, anyarray, anynonarray, 或者anyenum),特殊参数$0将被创建。它的数据类型将实际的返回函数的类型,从实际的输入类型返回(见Section 35.2.5)。这运行这个函数访问这个实际的返回类型如Section 39.3.3显示的那样。$0初始值为空并且能够被函数修改,如果需要,它可以用于保留返回值,虽然这不是必须的。$0也可以被给予一个别名。例如,这个函数能在任意一个有+操作符的数据类型上工作:
- CREATE FUNCTION add_three_values(v1 anyelement, v2 anyelement, v3 anyelement)
- RETURNS anyelement AS $$
- DECLARE
- result ALIAS FOR $0;
- BEGIN
- result := v1 + v2 + v3;
- RETURN result;
- END;
- $$ LANGUAGE plpgsql
声明一个或者多个多态类型的输出参数也是同样的效果。这种情况下这个特殊的$0参数将不会被用到,这个输出参数本身也是同样的作用,例如:
- CREATE FUNCTION add_three_values(v1 anyelement, v2 anyelement, v3 anyelement,
- OUT sum anyelement)
- AS $$
- BEGIN
- sum := v1 + v2 + v3;
- END;
- $$ LANGUAGE plpgsql;
39.3.2. 别名
newname ALIAS FOR oldname;
这个ALIAS语法比以前的章节中介绍的更加普通:你可以为任意一个变量声明一个别名,不只是函数的参数。这实际的用途是用预定义的名字为变量定义不同的名字,如触发器过程中的NEW或者OLD。 例子:
- DECLARE
- prior ALIAS FOR old;
- updated ALIAS FOR new;
因此,ALIAS使同样的对象有两种不同的方式命名,如果不限制的使用,将会变得混乱。这种方法最好只用于覆盖预定义的名字。
最后,贴出解决上面这个问题的存储过程吧:
- CREATE OR REPLACE FUNCTION message_deletes(ids "varchar", userid int8)
- RETURNS int4 AS
- $BODY$
- DECLARE
- r RECORD;
- del bool;
- num int4 := 0;
- sql "varchar";
- BEGIN
- sql := 'select id,receiveuserid,senduserid,senddelete,receivedelete from message where id in (' || ids || ')';
- FOR r IN EXECUTE sql LOOP
- del := false;
- IF r.receiveuserid=userid and r.senduserid=userid THEN
- del := true;
- ELSEIF r.receiveuserid=userid THEN
- IF r.senddelete=false THEN
- update message set receivedelete=true where id = r.id;
- ELSE
- del := true;
- END IF;
- ELSEIF r.senduserid=userid THEN
- IF r.receivedelete=false THEN
- update message set senddelete=true where id = r.id;
- ELSE
- del := true;
- END IF;
- END IF;
- IF del THEN
- delete from message where id = r.id;
- num := num + 1;
- END IF;
- END LOOP;
- return num;
- END;
- $BODY$
- LANGUAGE 'plpgsql' VOLATILE;
下面的例子是要调用一个存储过程自动创建对应的一系列表:
- CREATE OR REPLACE FUNCTION create_table_for_client(id int)
- RETURNS integer AS
- $BODY$
- DECLARE
- num int4 := 0;
- sql "varchar";
- BEGIN
- sql := 'create table _' || id || '_company(id int, name text)';
- EXECUTE sql;
- sql := 'create table _' || id || '_employee(id int, name text)';EXECUTE sql;
- sql := 'create table _' || id || '_sale_bill(id int, name text)';EXECUTE sql;
- .......
- return num;
- END;
- $BODY$ LANGUAGE plpgsql VOLATILE
自动创建序列
第一个例子
- CREATE OR REPLACE FUNCTION auto_gen_seq() RETURNS bigint AS
- $BODY$
- DECLARE
- rd RECORD;
- num int4 := 0;
- sql "varchar";
- seq_sql varchar;
- BEGIN
- sql := 'SELECT tablename FROM pg_tables WHERE tablename NOT LIKE ''pg%'' AND tablename NOT LIKE ''sql_%'' ORDER BY tablename;';
- FOR rd IN EXECUTE sql LOOP
- seq_sql:='CREATE SEQUENCE SQ_'||rd.tablename||' START 1000000 CACHE 30;';
- BEGIN
- EXECUTE seq_sql;
- EXCEPTION
- WHEN TOO_MANY_ROWS THEN
- RAISE EXCEPTION 'employee % not unique', seq_sql;
- WHEN OTHERS THEN
- return -1;
- END;
- num := num + 1;
- END LOOP;
- return num;
- END;
- $BODY$
- LANGUAGE plpgsql VOLATILE NOT LEAKPROOF
- COST 100;
调用:
- select auto_gen_seq()
第二个例子
- -- Function: auto_gen_seq(character)
- -- DROP FUNCTION auto_gen_seq(character);
- CREATE OR REPLACE FUNCTION auto_gen_seq("tbName" character)
- RETURNS character varying AS
- $BODY$/*
- 调用示例:
- SELECT tablename as tableName,
- '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
- ,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;
- */
- DECLARE
- rd RECORD;
- seq_sql varchar;
- flag_str varchar;
- sq_name varchar;
- sq_datetime varchar;
- BEGIN
- 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);';
- BEGIN
- EXECUTE seq_sql;
- EXCEPTION
- WHEN OTHERS THEN
- flag_str:='失败';
- END;
- --sq_name:=replace(replace($1, 'TB_', ''), 'RH_', '');
- --sq_name:=replace(replace(sq_name, 'tb_', ''), 'rh_', '');
- 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_', '');
- /*
- seq_sql:='drop SEQUENCE '||sq_name||';';
- BEGIN
- EXECUTE seq_sql;
- EXCEPTION
- WHEN OTHERS THEN
- flag_str:='失败';
- END;
- */
- seq_sql:='CREATE SEQUENCE '||sq_name||' START 1000000 CACHE 30;';
- BEGIN
- EXECUTE seq_sql;
- EXCEPTION
- WHEN OTHERS THEN
- return '失败,创建序列';
- END;
- sq_datetime:=to_timestamp(current_date||' '||current_time,'yyyy-mm-dd hh24:mi:ss') ;
- 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||''');';
- BEGIN
- EXECUTE seq_sql;
- EXCEPTION
- WHEN OTHERS THEN
- return '失败,插入序列信息';
- END;
- return '成功';
- END;
- $BODY$
- LANGUAGE plpgsql VOLATILE STRICT
- COST 100;
- ALTER FUNCTION auto_gen_seq(character)
- OWNER TO postgres;
调用
- SELECT tablename as tableName,
- '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
- ,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;
pgsql 的函数的更多相关文章
- pgsql 聚合函数array_to_string,ARRAY_AGG
array_to_string--将sql中的数组转为字符串 ARRAY_AGG--将sql中的数据转为数组处理 以下给大家一个简单的例子即可体会: 1.需求 2.数据库中原数据 1.pn ...
- PostgreSQL中的AnyEnum例子
建立函数: CREATE OR REPLACE FUNCTION enumtest(anyenum) RETURNS text AS $$ ::text; $$ LANGUAGE SQL; 建立enu ...
- 关于 pgsql 数据库json几个函数用法的效率测试
关于 pgsql 数据库json几个函数用法的效率测试 关于pgsql 几个操作符的效率测试比较1. json::->> 和 ->> 测试方法:单次运行100次,运行10个单次 ...
- 一个可能有用的封闭PGSQL操作的PYTHON函数
URL: http://www.linuxyw.com/517.html 一般操作: import psycopg2 连接数据库 conn = psycopg2.connect(database=db ...
- PL/pgSQL函数带output参数例子
例子1,不带returns : [postgres@cnrd56 bin]$ ./psql psql () Type "help" for help. postgres=# CRE ...
- Pgsql数据库jsonb操作函数集合
CREATE OR REPLACE FUNCTION "json_object_del_path"( "json" json, "key_path&q ...
- PostgreSQL-PL/pgSQL
参考: https://wiki.postgresql.org/wiki/9.1%E7%AC%AC%E4%B8%89%E5%8D%81%E4%B9%9D%E7%AB%A0 摘记: PL/pgSQL是 ...
- postgresql 函数返回结果集(zz)
pgsql function 系列之一:返回结果集--------------------------------------------------------------------------- ...
- pgsql 常用的命令
pgsql 常用的命令:1. 创建数据库create database name with owner username; 2. 创建用户create role with createdb ;crea ...
随机推荐
- io机制沉思录:分层与管理
io模型的核心是内核kernel与应用(线程)的关系: 内核与应用的联系:数据状态信号和数据本身: 一.分层模型: 应用层——内核层——设备层 https://www.cnblogs.com/feng ...
- rsync性能终极优化【Optimize rsync performance】
前言 将文件从一台计算机同步或备份到另一台计算机的快速简便的方法是使用rsync.我将介绍通常用于备份数据的命令行选项,并显示一些选项以极大地将传输速度从大约20-25 MB / s加快到90 MB ...
- K-means 和 EM 比较
回顾 前几篇对 k-means 有过理解和写了一版伪代码, 因为思想比较非常朴素, 就是初始化几个中心点, 然后通过计算距离的方式, "物以类聚", 不断迭代中心点, 最后收敛, ...
- Python从零开始——迭代器与生成器
一:迭代器 二:生成器
- mysql-5..6.23-win64.zip安装及配置
MySQL是一个小巧玲珑但功能强大的数据库,目前十分流行.但是官网给出的安装包有两种格式,一个是msi格式,一个是zip格式的.很多人下了zip格式的解压发现没有setup.exe,面对一堆文件一头雾 ...
- Spring(005)-多环境Profile
多个环境下的配置应该怎么进行,比如数据库连接字符,多个环境不同,spring的方案,大概总结如下. 例子,数据库配置. 定义一个获取数据库链接的接口 public interface DataConn ...
- 2019面向对象程序设计(Java) 第17周-18周学习指导及要求
2019面向对象程序设计(Java)第17周-18周学习指导及要求 (2019.12.20-2019.12.31) 学习目标 (1) 理解和掌握线程的优先级属性及调度方法: (2) 掌握线程同步的 ...
- 201871010121-王方-《面向对象(java)程序设计对象》第十周学习总结
王方第九周Java实验总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.co ...
- 201871010128-杨丽霞《面向对象程序设计(java)》第十六周学习总结
201871010128-杨丽霞<面向对象程序设计(java)>第十六周学习总结(1分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-dai ...
- VirtualBox + vagrant 使用虚拟机
1.VirtualBox下载地址 https://www.virtualbox.org/wiki/Downloads 2.vagrant下载地址 https://www.vagrantup.com/d ...