postgreSQL之存儲過程 發布於 6 個月前 (10月23日) - 1524 次檢閱

以下是自己結合postgreSQL文檔手冊總結整理的入門手札,如有不嚴謹,請到官方文檔手冊查看:http://www.postgres.cn/docs/10/index.html


基於SQL的存儲過程

什麼是sql函數?
  1. SQL函數包體是一些可執行的SQL語言。同時包含1條以上的查詢,但是函數只返回最後一個查詢(必須是SELECT)的結果。
  2. 簡單情況下,返回最後一條查詢結果的第一行。
  3. 如果最後一個查詢正好根本不返回行,將會返回空值。
  4. 除非SQL函數聲明為返回void,否則最後一條語句必須是SELECT
  5. 如果需要該函數返回最後一條SELECT語句的所有行,可以將函數的返回值定義為集合,即SETOF sometype,或者等效地聲明它為RETURNS TABLE(columns)

創建sql函數,如:

CREATE OR REPLACE FUNCTION function_name([ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ])  [RETURNS rettype]  AS $$      $BODY$;  $$ LANGUAGE SQL;

接下來用一個例子,如最簡單的SQL函數沒有參數並且簡單地返回一個基本類型:

CREATE or replace FUNCTION one()  	RETURNS  integer AS  $body$      SELECT 1;  $body$  LANGUAGE SQL;  ----------  select one();  ------  one  1

如創建一個add函數,返回兩者的入參值:

CREATE or replace FUNCTION add(a integer,b integer)  	RETURNS  integer AS  $body$      SELECT a+b;  $body$  LANGUAGE SQL;  ------  select add(1,2)  ----  add  3

還有另外一種方式,即能省掉參數名而使用數字$n,$n這樣的標識符來使用參數,如:

CREATE or replace FUNCTION add(a integer,b integer)  	RETURNS  integer AS  $body$      SELECT $1+$2;  $body$  LANGUAGE SQL;

但個人覺得這種方式不怎麼友好,就是可讀性雞巴的差~

上面的兩個例子,都是只有入參,而沒出參,接下來這個例子將同時包含輸入參數和輸出參數;由於存在輸出參數;這裡不需要returns部分,如:

CREATE OR REPLACE FUNCTION add1(in a integer, in b integer,out c integer)  AS $body$      SELECT a+b;  $body$  LANGUAGE SQL;  -----------------  select add1(1,2);  ---------------  add1  3

還記得之前sql函數的介紹嗎?sql函數包體是一些可執行的SQL語言。同時包含1條以上的查詢,但是函數只返回最後一個查詢(必須是SELECT)的結果。所以,在sql函數包體中,不一定是SELECT語句,可以是其它任意合法的SQL。但最後一條SQL必須是SELECT語句並且該SQL的結果將作為該函數的輸出結果。接下來就做一個測試,如:

CREATE OR REPLACE FUNCTION add2(in a integer, in b integer,out c integer,out d integer)  AS  $body$  	SELECT a+b,a*b;  	delete from test_array where id =1;  	SELECT a+b+a,a*b*a;    $body$  LANGUAGE SQL;  --------  select * from add2(1,2);  ---------  c	d  4	2

繼續上面的sql函數介紹-->除非SQL函數聲明為返回void,否則最後一條語句必須是SELECT,接下來我這邊就直接返回void,所以就可以沒有select,如:

CREATE OR REPLACE FUNCTION delete_array(id integer)  RETURNS void AS  $body$  	delete from test_array where id =id;  $body$  LANGUAGE SQL;

還有就是,當一個表裡面含有多條記錄咋辦呢?帶著疑問看例子吧騷年:

CREATE OR REPLACE FUNCTION select_array_er()  RETURNS integer AS  $body$  	select id from test_array_er;  $body$  LANGUAGE SQL;  ------  select  select_array_er();//我這邊id就只有兩條,1和2  -------  select_array_er  2

所以,實踐的真理告訴我們,是返回最後結果行。 等等,你肯定會問,那麼我要返回所有id怎麼弄?來,叔叔帶你去看金魚:

CREATE OR REPLACE FUNCTION select_array_er2()  RETURNS setof INTEGER AS  $body$  	select id from test_array_er;  $body$  LANGUAGE SQL;  -----  select  select_array_er2();  -----  select_array_er2  2  1

所以,如果需要返回該函數最後一條SELECT語句的所有行,可以將函數的返回值定義為集合,即SETOF sometype。

基於PL/PgSQL的存儲過程

PL/pgSQL是一種用於PostgreSQL資料庫系統的可載入的過程語言。PL/pgSQL的設計目標是創建一種這樣的可載入過程語言:

  • 可以被用來創建函數和觸發器過程
  • 對SQL語言增加控制結構
  • 可以執行複雜計算
  • 繼承所有用戶定義類型、函數和操作符
  • 可以被定義為受伺服器信任
  • 便於使用
PL/PgSQL的存儲過程的塊結構

PL/pgSQL是一個塊結構語言。函數定義的所有文本都必須是一個塊。 一個塊用下面的方法定義:

  • PL/pgSQL程式由三個部分組成,即:
    • 聲明部分
    • 執行部分
    • 異常處理部分

PL/pgSQ結構如:

[ <<label>> ]  [ DECLARE      declarations ]      --聲明部分: 在此聲明PL/SQL用到的變數,類型及游標.  BEGIN      statements      -- 執行部分:  過程及SQL語句,即程式的主要部分  EXCEPTION     -- 執行異常部分: 錯誤處理      END [ label ];

在一個塊中的每一個聲明和每一個語句都由一個分號終止。如上所示,出現在另一個塊中的塊必須有一個分號在END之後。不過最後一個結束函數體的END不需要一個分號。

PL/PgSQL的存儲過程的變數聲明

變數聲明的一般語法是:

name [ CONSTANT ] type [ COLLATE collation_name ] [ NOT NULL ] [ { DEFAULT | := | = } expression ];

PL/pgSQL變數可以是任意 SQL 數據類型,例如integer、varchar和char。

這跟oracle中的存儲過程聲明變數是一樣的 例如:

user_id integer;  quantity numeric(5);  url varchar;  myrow tablename%ROWTYPE;--行類型  myfield tablename.columnname%TYPE;--複製類型  arow RECORD;--記錄類型
PL/PgSQL的存儲過程的參數

聲明一個參數的語法如下:

name [in|out|in out] type

如果只指定輸入參數類型,不指定參數名,則函數體里一般用$1,$n這樣的標識符來使用參數。如:

CREATE OR REPLACE FUNCTION demo(NUMERIC)  RETURNS NUMERIC  AS $$  BEGIN      RETURN $1 * 0.8;  END;  $$  LANGUAGE PLPGSQL;

但該方法可讀性不好,最後還是在聲明參數類型時同時聲明相應的參數名,如:

CREATE OR REPLACE FUNCTION demo(total NUMERIC)  RETURNS NUMERIC  AS $$  BEGIN      RETURN total * 0.8;  END;  $$  LANGUAGE PLPGSQL;
PL/PgSQL的存儲過程的注釋

在PL/SQL里,可以使用兩種符號來寫注釋,即:

  1. 第一種是使用 雙-(雙減號)它的作用範圍是只能在一行有效(類似java 單行注釋//)
  2. 第二種就是一行或多行注釋,使用的是/* */表示
簡單的一個PL/PgSQL的存儲過程例子
CREATE OR REPLACE FUNCTION somefunc()  	RETURNS integer AS $body$  DECLARE      somenum integer := 30;  BEGIN      -- 這是單行注釋      RAISE NOTICE '這是一條提示語 %', somenum;      somenum := 50;  	/*  		這是多行注釋  	*/      RAISE NOTICE 'somenum here is %', somenum;      RETURN somenum;  	--錯誤捕獲  	EXCEPTION  		WHEN others THEN      		RAISE EXCEPTION '(%)', SQLERRM;  END;  $body$  LANGUAGE plpgsql;
PL/PgSQL的存儲過程的異常錯誤處理

在上面例子,其實已經有了處理異常錯誤的語句了。具體它是幹嘛的呢?

其實阿,在PL/pgSQL函數中,如果沒有異常捕獲,函數會在發生錯誤時直接退出,與其相關的事物也會隨之回滾。我們可以通過使用帶有EXCEPTION子句的BEGIN塊來捕獲異常並使其從中恢復。見如下聲明形式:

[ <> ]  [ DECLARE      declarations ]  BEGIN      statements  EXCEPTION    WHEN condition [ OR condition ... ] THEN              handler_statements    WHEN condition [ OR condition ... ] THEN           handler_statements  END;

如果沒有錯誤發生,只有BEGIN塊中的statements會被正常執行,然而一旦這些語句中有任意一條發生錯誤,其後的語句都將被跳過,直接跳轉到 EXCEPTION塊的開始處。此時系統將搜索異常條件列表,尋找匹配該異常的第一個條件,如果找到匹配,則執行相應的 handler_statements,之後再執行END的下一條語句。如果沒有找到匹配,該錯誤就會被繼續向外拋出,其結果與沒有EXCEPTION子 句完全等同。如果此時handler_statements中的語句發生新錯誤,它將不能被該EXCEPTION子句捕獲,而是繼續向外傳播,交由其外層 的EXCEPTION子句捕獲並處理。

在PostgreSQL中可以利用RAISE語句報告資訊和拋出錯誤,其聲明形式為:

RAISE level 'format' [, expression [, ...]];

例如:

raise notice 'My name is %, I am a %.', 'glj', 'Handsome boy';

更多可到:https://199604.com/1339 查看

Tags: