PostgreSQL存儲過程(2)-基於PL/PgSQL的存儲過程


介紹

  PL/pgSQL 是PostgreSQL 數據庫系統的一個可加載的過程語言。 PL/pgSQL 的設計目標是創建一種可加載的過程語言,可以 用於創建函數和觸發器過程, 為SQL 語言增加控制結構, 執行復雜的計算 繼承所有用戶定義類型、函數、操作符, 定義為被服務器信任的語言。PL/pgSQL創建的函數可以在那些使用內置函數一樣的情形下使用。 比如,可以創建復雜的條件計算函數,並隨后將之用於定義操作符或者用於函數索引中。

使用PL/pgSQL的優點

  • SQL是PostgreSQL和大多數其它關系型數據庫的命令語言。
  • 它是可移植的並且容易學習使用。但是所有SQL語句都必須由數據庫服務器獨立地執行.
  • 通過PL/pgSQL,可以把運算塊和一系列命令在數據庫服務器內部組成一個塊, 這樣就擁有了過程語言的能力並且簡化 SQL 的使用, 因而節約了大量的時間,因為不需要進行客戶端/服務器通訊。
  • 消除了服務器和客戶端之間的往返通信。
  • 客戶端不需要的中間結果無需在服務器端和客戶端來回傳遞。
  • 不需要額外的語法分析步驟。比起不使用存儲函數來,這樣做能夠產生明顯的性能提升

塊結構

  PL/pgSQL是一個塊結構語言。函數定義的所有文本都必須是一個塊。一個塊用下面的方法定義:
  PL/pgSQL程序由三個部分組成,即聲明部分、執行部分、異常處理部分。
  PL/pgSQL的結構如下:

DECLARE 
   --聲明部分: 在此聲明PL/SQL用到的變量,類型及游標.
 BEGIN
   -- 執行部分:  過程及SQL語句,即程序的主要部分
 EXCEPTION
   -- 執行異常部分: 錯誤處理
 END;

其中:執行部分不能省略。

  • 塊中的每一個declaration和每一條statement都由一個分號終止
  • 塊支持嵌套,嵌套時子塊的END后面必須跟一個分號,最外層的塊END后可不跟分號
  • BEGIN后面不必也不能跟分號,END后跟的label名必須和塊開始時的標簽名一致
  • 所有關鍵字都不區分大小寫。標識符被隱含地轉換成小寫字符,除非被雙引號包圍
  • 聲明的變量在當前塊及其子塊中有效,子塊開始前可聲明並覆蓋(只在子塊內覆蓋)外部塊的同名變量
  • 變量被子塊中聲明的變量覆蓋時,子塊可以通過外部塊的label訪問外部塊的變量

變量聲明

聲明一個變量的語法如下:

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

這跟oracle中的存儲過程聲明變量是一樣的。如

name text := 'lottu';
empno numeric := 110;

PL/pgSQL程序設計中的變量定義與SQL的標識符定義的要求相同。要求和限制有:

  • 標識符名不能超過30字符;
  • 第一個字符必須為字母;
  • 不分大小寫;
  • 不能用’-‘(減號);
  • 不能是SQL保留字。

參數

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

name [in|out|in out] type

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

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

但該方法可讀性不好,此時可以為$n參數聲明別名,然后可以在函數體內通過別名(ALIAS FOR)指向該參數值。

CREATE OR REPLACE FUNCTION discount(NUMERIC)
RETURNS NUMERIC
AS $$
DECLARE
    total ALIAS FOR $1;
BEGIN
    RETURN total * 0.8;
END;
$$ LANGUAGE PLPGSQL;

幸好PostgreSQL提供另外一種更為直接的方法來聲明函數參數,即在聲明參數類型時同時聲明相應的參數名。

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

注釋

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

使用雙 ‘-‘ ( 減號) 加注釋PL/SQL允許用 – 來寫注釋,它的作用范圍是只能在一行有效。如:  
-- This is a single-line comments ...
使用 /*   */  來加一行或多行注釋,如:
/*
 This is a multiline comment ...
*/

案例分析

  采用跟oracle的plsql存儲過程做對比。

--使用PL/PgSQL語言的函數定義如下:
CREATE FUNCTION somefunc() RETURNS integer AS $$
DECLARE
    quantity integer := 30;
BEGIN
    -- Prints 30
    RAISE NOTICE 'Quantity here is %', quantity;
    quantity := 50;
    -- Create a subblock
    DECLARE
        quantity integer := 80;
    BEGIN
        -- Prints 80
        RAISE NOTICE 'Quantity here is %', quantity;
    END;
    -- Prints 50
    RAISE NOTICE 'Quantity here is %', quantity;
    RETURN quantity;
END;
$$ LANGUAGE plpgsql;
-- 使用plsql語言編寫如下:
DECLARE
  quantity number := 30;
BEGIN
  -- Prints 30
  DBMS_OUTPUT.PUT_LINE('Quantity here is ' || quantity);
  quantity := 50;
  -- Create a subblock
    DECLARE
      quantity number := 80;
    BEGIN
      -- Prints 80
      DBMS_OUTPUT.PUT_LINE('Quantity here is ' || quantity);
    END;
    -- Prints 50
  DBMS_OUTPUT.PUT_LINE('Quantity here is ' || quantity);
END;

該案例而說;postgres存儲過程跟oracle存儲過程結構很相似。postgres中的'RAISE NOTICE'替換了oracle中'DBMS_OUTPUT.PUT_LINE'。

函數重載(Overwrite)

  在PostgreSQL中,多個函數可共用同一個函數名,但它們的參數必須得不同。這一規則與面向對象語言(比如Java)中的函數重載類似。也正因如此,在PostgreSQL刪除函數時,必須指定其參數列表,如:

DROP FUNCTION get_array(anyelement, anyelement);

另外,在實際項目中,經常會用到CREATE OR REPLACE FUNCTION去替換已有的函數實現。如果同名函數已存在,但輸入參數列表不同,會創建同名的函數,也即重載。如果同名函數已存在,且輸入輸出參數列表均相同,則替換。如果已有的函數輸入參數列表相同,但輸出參數列表不同,則會報錯,並提示需要先DROP已有的函數定義。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM