[PostgreSQL] 我的PL/pgSQL授課用的範例-進銷存(一)-進貨篇
沒想到這裡我已有12年沒更新了. 現在重回來寫Blog看看, 慢慢再清理這裡的佈局和內容.
走在這條資訊管理的不歸路, 不知不覺30年了, 一路全在業界打滾, 有得有失, 心境也隨著修行, 世事無常, 留下點微薄的經驗貢獻給需要的人.
全文連結在: https://oss-tw.blogspot.com/2021/02/postgresql-plpgsql.html
全球最先進的開放源碼資料庫系統! PostgreSQL 以全球最自由且不受用途限制的 BSD 授權協議發佈, 擁有龐大的全球開發者/用戶社群, PostgreSQL 為企業級應用特性亦完整且高度相容於 ISO/ANSI SQL 國際標準, 高可用性(HA)及數據儲存品質倫美與持續超越 Oracle, DB2... 等商業型資料庫管理系統, TOC(整體擁有成本)更遠低於商業型 DBMS 達數百倍.
沒想到這裡我已有12年沒更新了. 現在重回來寫Blog看看, 慢慢再清理這裡的佈局和內容.
走在這條資訊管理的不歸路, 不知不覺30年了, 一路全在業界打滾, 有得有失, 心境也隨著修行, 世事無常, 留下點微薄的經驗貢獻給需要的人.
全文連結在: https://oss-tw.blogspot.com/2021/02/postgresql-plpgsql.html
PL/pgSQL 是 PostgreSQL 內置的可選預儲程序(Stored Procured)語言之一, 也是當中的效能與功能最強的。在這系列我們將學習如何撰寫 PL/pgSQL 的存儲函數/函式(Function)。
所有的 PL/pgSQL 函數遵循的結構, 看起來都如同下面的形式。
CREATE OR REPLACE FUNCTION fnsomefunc(numtimes integer, msg text)
RETURNS text AS
$
DECLARE
strresult text;
BEGIN
strresult := '';
IF numtimes > 0 THEN
FOR i IN 1 .. numtimes LOOP
strresult := strresult || msg || E'\r\n';
END LOOP;
END IF;
RETURN strresult;
END;
$
LANGUAGE 'plpgsql' IMMUTABLE
SECURITY DEFINER
COST 10;
-- 我們呼叫這個函數它將回傳10次'hello there's'且回傳處理於單一的文本(text)欄位中.
SELECT fnsomefunc(10, 'Hello there');
這個 PL/pgSQL 函數的基本構成如下:
PL/pgSQL 對條件限制的邏輯式是成對的結構. 在上面的範例中我們看到了簡單的 IF THEN。同樣也存在於 IF .. ELSIF ..ELSIF END IF, IF ..ELSE ..END IF。我們將在上面的示例上做一個改變。
CREATE OR REPLACE FUNCTION fnsomefunc(numtimes integer, msg text)你說得對!
RETURNS text AS
$
DECLARE
strresult text;
BEGIN
strresult := '';
IF numtimes = 42 THEN
strresult := '';你不能這樣做。麻煩不要濫用我們的慷慨。
ELSIF numtimes > 0 AND numtimes < 100 THEN
FOR i IN 1 .. numtimes LOOP
strresult := strresult || msg || E'\r\n';
END LOOP;
ELSE
strresult := '';。
IF numtimes <= 0 THEN
strresult := strresult || '你是一個 bozo';我不知道你以為你是誰。
ELSIF numtimes > 1000 THEN
strresult := strresult || '。
你的意向失去了控制';
END IF;
END IF;
RETURN strresult;
END;
$
LANGUAGE 'plpgsql' IMMUTABLE;
SELECT fnsomefunc(42, 'Hello there');
SELECT fnsomefunc(200, 'Hello there');
SELECT fnsomefunc(5000, 'Hello there');
在 PL/pgSQL 中提供的基本控制流結構是:
更新:2007-09-09
對映章節:
內容:
使用 PL/pgSQL 不外乎就是撰寫資料庫的預儲程序(Stored Procedure)、函數(Function)、觸發器(Trigger) 等。設計這些內部程序,其中除了迴圈、真假值判斷、回傳等等特別需求的語法外,主要的內容還是由各種 SQL 查詢命令或是呼叫其他已存在的函數所構成。由於使用 PL/pgSQL 呼叫其他函數或執行SQL命令時,多半是要等待回傳值、資料列並更進一步處理,所以與平時用前端程式或SQL命令列對函數與SQL指令的操作上,有比較不同的習慣性用法。要了解在 PL/pgSQL 處理各種呼叫查詢,必須從回傳值處理的角度去深入。
以下是幾個常用處理函數和SQL命令回傳值的方法:
SELECT * INTO rs FROM mytable;
然後可讀取回傳資料列的各欄位內容:
rs.id
rs.name
rs.address
...
註:此 SELECT INTO 使用方法很特別,並非是你想的那樣,請參考下文說明。
SELECT address INTO addr FROM mytable;
EXECUTE myfunction();
PERFORM myfunction();
註:EXECUTE 和 PERFORM 的詳細差異不在本文討論範圍,請參考官方說明文件。
在資料整理時,我們常碰到有些資料需要往前移動,有些則要往後移動,尤其在資料的顯示流程規劃上就常常要使用到這種 功能。可是傳統資料庫的排序功能,不外乎就是使用日期、時間、資料編號做為排序依據,然後利用 ORDER BY 命令達成資料排序的目的,除此之外,我們無法動態調整資料列的先後次序。
一種解決辦法是為每個資料列增加新的欄位﹝例子中取名為mytable_after﹞,用來記錄該筆資料列的前一筆資料編號。所以我們在讀取資料時就使用該欄位記錄的值,逐一列出每筆資料。操作流程大致上是:
讀取第一筆資料 A﹝mytable_after 為 0﹞
→ 讀取欄位 mytable_after = A 的第二筆資料 B→ 重覆操作直到找不到下一筆資料
PostgreSQL 動態排列實作例子:
CREATE OR REPLACE FUNCTION mytable_dynlist()
RETURNS SETOF mytable AS
$BODY$DECLARE
rscount Integer;
rsnext Integer;
rs record;
BEGINselect count(*) INTO rscount from mytable;
rsnext = 0;
FOR i IN 1 .. rscount LOOP
SELECT * INTO rs from mytable where mytable_after = rsnext LIMIT 1;
rsnext = rs.mytable_id;
RETURN NEXT rs;
END LOOP;
END;$BODY$
LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION mytable_dynlist() OWNER TO somebody;
當 資料不多時,這種在資料庫內部處理動態排列很省事,在前端的程式也很好寫,但是,資料量一大,這種方式會造成 SQL Server 相當大的負擔。所以,當資料量多或是在前端程式有做多台機器的負載平衡,還是建議在前端先將所有要排序的資料下載後,在前端的程式做排序處理。
PostgreSQL 資料分頁 Stored Procedure 實作例子:CREATE OR REPLACE FUNCTION mytable_list(ps bigint, page bigint)
RETURNS SETOF mytable AS
$BODY$DECLARE
rs mytable;
BEGIN
FOR rs IN select * from mytable LIMIT ps OFFSET ps*(page-1) LOOP
RETURN NEXT rs;
END LOOP;
END;$BODY$
LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION mytable_list(ps bigint, page bigint) OWNER TO somebody;
延伸閱讀(Link):ps - 設定每一頁的資料列數量page - 指定目前讀取的頁碼
增進 SQL 處理效率的一個很重要的方法就是使用 Stored Procedure ,一般商用級以上的資料庫系統都會內建這種功能。
以下是在 PostgreSQL 中建立一個 Stored Procedure 的最簡單例子:
-- 執行結果:執行 select * from mytable where table_id = id 並回傳所有符合的資料列
CREATE OR REPLACE FUNCTION pg_myfunc(id integer)
RETURNS SETOF mytable AS
$BODY$DECLARE
rs RECORD;
BEGIN
FOR rs IN select * from mytable where table_id = id LOOP
RETURN NEXT rs;
END LOOP;
END;$BODY$
LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION pg_myfunc(id integer) OWNER TO somebody;
如同 Oracle PL/SQL一般,PostgreSQL也有自己的程序語言 PL/pgSQL,其中最常用到的幾種語法使用:
IF 判斷式
IF ... THEN
ELSIF ... THEN
ELSE
ENDIF;
FOR LOOP迴圈
FOR i IN 1 .. 10 LOOP
...
END LOOP;
當找不到任何符合的資料列時
SELECT * FROM mytable WHERE mytable_id = id;
IF not found THEN
-- 找不到任何符合的資料列時執行這裡的程序END IF;
全部的 Function 都建立完成了,接著就要開始使用已建立的 Stored Procedure。
執行 Functions 有兩種SQL命令可以使用:
Function 沒有回傳值時使用 SELECT pg_myfunc();
Function 有回傳值時使用 SELECT * FROM pg_myfunc();
|
|
| PostgreSQL 8 DBA 專業指南中文版 |
| 書籍內容討論與更多下載區(造訪此群組)
目錄下載: PostgreSQL_8 _DBA_Index_zh_TW.pdf (更新:2007-05-18) |