PL/pgSQL sql
全部 SQL 语句都必须由数据库服务器独立地执行,这就意味着你的客户端应用必须把每条命令发送到数据库服务器, 等待它处理这个命令,接收结果,作一些运算,而后给服务器发送另一条命令。 全部这些东西都会产生进程间通信,而且若是你的客户端在另一台机器上甚至还会致使网络开销。 数据库
若是使用了PL/pgSQL,那么你能够把一块运算和一系列命令在数据库服务器里面组成一个块, 这样就拥有了过程语言的力量而且简化 SQL 的使用,于是节约了大量的时间,由于你用不着付出客户端/服务器通信的过热。 这样可能产生明显的性能提高。 express
PL/pgSQL引号 缓存
PL/pgSQL函数的代码都是在CREATE FUNCTION里以一个字串文本的方式声明的。若是你用两边包围单引号的常规方式写字串文本,那么任何函数体内的单引号都必须写双份;相似的是反斜杠也必须双份。 双份引号很是乏味,在更复杂的场合下,代码可能会让人难以理解, 由于你很容易发现本身须要半打甚至更多相连的引号。 咱们建议你用"美圆符包围"的字串文原本写函数体。 使用美圆符包围的时候,你从不须要对任何引号写双份, 只须要为每层引号包围嵌套选择一个不一样的美圆符号包围分隔符便可。 好比,你可能这么写CREATE FUNCTION命令. 安全
声明 服务器
name[ CONSTANT ]type[ NOT NULL ] [ { DEFAULT | := }expression];
user_id integer; quantity numeric(5); url varchar; myrow tablename%ROWTYPE; myfield tablename.fieldname%TYPE; arow RECORD;函数别名
传递给函数的参数都是用$1,$2,等等这样的标识符。 为了增长可读性,咱们能够为$n参数名声明别名。 网络
CREATE FUNCTION sales_tax(subtotal real) RETURNS real AS $$ BEGIN RETURN subtotal * 0.06; END; $$ LANGUAGE plpgsql;同下面:
CREATE FUNCTION sales_tax(REAL) RETURNS real AS $$ DECLARE subtotal ALIAS FOR $1; BEGIN RETURN subtotal * 0.06; END; $$ LANGUAGE plpgsql;
拷贝类型: ide
user_id users.user_id%TYPE;
行类型: 函数
nametable_name%ROWTYPE; namecomposite_type_name;一个复合类型变量叫作 行变量(或者 row-type变量)。 这样的一个变量能够保存一次SELECT或者FOR命令结果的完整一行,只要命令的字段集匹配该变量声明的类型。 行数值的独立的字段是使用经常使用的点表示法访问的,好比rowvar.field。
CREATE FUNCTION merge_fields(t_row table1) RETURNS text AS $$ DECLARE t2_row table2%ROWTYPE; BEGIN SELECT * INTO t2_row FROM table2 WHERE ... ; RETURN t_row.f1 || t2_row.f3 || t_row.f5 || t2_row.f7; END; $$ LANGUAGE plpgsql; SELECT merge_fields(t.*) FROM table1 t WHERE ... ;记录类型:
表达式: oop
计算一个表达式或者一个命令,可是却丢弃其结果(一般由于咱们常常调用一些存在有用的反作用可是不存在有用结果值的函数)。 要在 PL/pgSQL 里干这件事, 你可使用PERFORM语句:
PERFORM query;
在使用动态命令的时候,你常常须要逃逸单引号。咱们建议包围你的函数体内固定文本的方法是美圆符包围。要插入到构造出来的查询中的动态数值也须要特殊的处理, 由于他们本身可能包含引号字符。
EXECUTE 'UPDATE tbl SET ' || quote_ident(columnname) || ' = ' || quote_literal(newvalue) || ' WHERE ...';为了安全,包含字段和表标识符的变量应该传递给函数quote_ident。 那些包含数值的变量,若是其值在构造出来态命令字串里应外是文本字串,那么应该传递给quote_literal。 它们俩都会采起合适的步骤把输入文本包围在单或双引号里而且对任何嵌入其中的特殊字符进行合适的逃逸处理。
获取结果状态
第一个方法是使用GET DIAGNOSTICS,它的形式以下:
GET DIAGNOSTICSvariable=item[ , ... ];
另一个判断命令效果的方法是一个类型为boolean的特殊变量FOUND。FOUND在每一个 PL/pgSQL 函数里开始都为假。它被下列语句设置:
一个SELECT INTO语句若是返回一行则设置FOUND为真,若是没有返回行则设置为假。
一个PERFORM语句若是生成(或抛弃)一行,则设置FOUND为真,若是没有生成行则为假。
若是至少影响了一行,那么UPDATE,INSERT,和DELETE语句设置FOUND为真,若是没有行受影响则为假。
FETCH语句若是返回行则设置FOUND为真, 若是不返回行则为假。
一个FOR语句若是迭代了一次或屡次,则设置FOUND为真,不然为假。这个规律适用于全部FOR语句的三种变体 (整数FOR循环,记录集的FOR循环,
从函数返回
RETURN expression;
带表达式的RETURN是用于终止函数, 而后expression的值返回给调用者。
RETURN NEXT expression;条件
IF语句让你能够根据某种条件执行命令。 PL/pgSQL有五种形式的IF:
IF ... THEN
IF ... THEN ... ELSE
IF ... THEN ... ELSE IF
IF ... THEN ... ELSIF ... THEN ... ELSE
IF ... THEN ... ELSEIF ... THEN ... ELSE
IF boolean-expression THEN statements [ ELSIF boolean-expression THEN statements [ ELSIF boolean-expression THEN statements...]] [ ELSE statements] END IF;简单循环
[ <<label>> ] LOOP statements END LOOP [ label];
LOOP -- 一些计算 IF count > 0 THEN EXIT; -- exit loop END IF; END LOOP;
LOOP -- 一些计算 EXIT WHEN count > 100; CONTINUE WHEN count < 50; -- 一些在 count 数值在 [50 .. 100] 里面时候的计算 END LOOP;
WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP -- 能够在这里作些计算 END LOOP;
FOR i IN 1..10 LOOP -- 这里能够放一些表达式 RAISE NOTICE 'i IS %', i; END LOOP; FOR i IN REVERSE 10..1 LOOP -- 这里能够放一些表达式 END LOOP;
CREATE FUNCTION cs_refresh_mviews() RETURNS integer AS $$ DECLARE mviews RECORD; BEGIN PERFORM cs_log('Refreshing materialized views...'); FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP -- 如今 "mviews" 里有了一条来自 cs_materialized_views 的记录 PERFORM cs_log('Refreshing materialized view ' || quote_ident(mviews.mv_name) || ' ...'); EXECUTE 'TRUNCATE TABLE ' || quote_ident(mviews.mv_name); EXECUTE 'INSERT INTO ' || quote_ident(mview.mv_name) || ' ' || mview.mv_query; END LOOP; PERFORM cs_log('Done refreshing materialized views.'); RETURN 1; END; $$ LANGUAGE plpgsql;捕获错误
INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones'); BEGIN UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones'; x := x + 1; y := x / 0; EXCEPTION WHEN division_by_zero THEN RAISE NOTICE 'caught division_by_zero'; RETURN x; END;声明游标
全部在 PL/pgSQL 里对游标的访问都是经过游标变量实现的, 它老是特殊的数据类型refcursor。建立一个游标变量的一个方法是把它声明为一个类型为refcursor的变量。 另一个方法是使用游标声明语法,一般是下面这样:
name CURSOR [ (arguments) ] FOR query;
DECLARE curs1 refcursor; curs2 CURSOR FOR SELECT * FROM tenk1; curs3 CURSOR (key integer) IS SELECT * FROM tenk1 WHERE unique1 = key;全部这三个变量都是类型为refcursor, 可是第一个能够用于任何命令,而第二个已经 绑定 了一个声明完整的命令,最后一个是绑定了一个带参数的命令。 (key将在游标打开的时候被代换成一个整数。)
打开游标
在你使用游标检索行以前,你必需宪打开它。
OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;该游标变量打开,而且执行给出的查询。游标不能是已经打开的, 而且它必需是声明为一个未绑定的游标。查询必须是一条SELECT,或者其它返回行的东西(好比EXPLAIN)。 查询是和其它在 PL/pgSQL 里的 SQL 命令平等对待的: 先代换 PL/pgSQL 的变量名,并且执行计划为未来可能的复用缓存起来。
OPEN curs1 FOR EXECUTE 'SELECT * FROM ' || quote_ident($1);
打开游标变量而且执行给出的查询。游标不能是已打开的,而且必须声明为一个未绑定的游标。命令是用和那些用于EXECUTE命令同样的方法声明的字串表达式, 这样,咱们就有了命令能够在两次运行间发生变化的灵活性。
打开一个绑定的游标
OPEN curs2; OPEN curs3(42);使用游标
FETCH curs1 INTO rowvar; FETCH curs2 INTO foo, bar, baz;FETCH从游标中检索下一行到目标中,目标能够是一个行变量,一个记录变量, 或者是一个逗号分隔的普通变量的列表。
CLOSE cursor;CLOSE关闭支撑在一个打开的游标下面的信使。 这样咱们就能够在事务结束以前施放资源,或者释放掉该游标变量,用于稍后再次打开。
CREATE TABLE test (col text); INSERT INTO test VALUES ('123'); CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS ' BEGIN OPEN $1 FOR SELECT col FROM test; RETURN $1; END; ' LANGUAGE plpgsql; BEGIN; SELECT reffunc('funccursor'); FETCH ALL IN funccursor; COMMIT;
全部在块里使用的变量都必须在一个块的声明段里声明。 (惟一的例外是一个FOR循环里的循环变量是在一个整数范围内迭代的,被自动声明为整数变量。