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循環裏的循環變量是在一個整數範圍內迭代的,被自動聲明爲整數變量。