35.4. 聲明

所有在塊裡使用的變量都必須在一個塊的聲明段裡聲明。 (唯一的例外是一個FOR循環裡的循環變量是在一個整數範圍內迭代的,被自動聲明為整數變量。)

PL/pgSQL變量可以用任意的 SQL 資料類型,比如 integervarcharchar

下面是一些變量聲明的例子︰

user_id integer;
quantity numeric(5);
url varchar;
myrow tablename%ROWTYPE;
myfield tablename.fieldname%TYPE;
arow RECORD;

一個變量聲明的一般性語法是︰

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

如果給出了DEFAULT子句,那麼它聲明了在進入該塊的時候賦予該變量的初始值。 如果沒有給出DEFAULT子句,那麼該變量初始化為 SQL 空值。 CONSTANT選項避免了該變量被賦值,這樣其數值在該塊的範圍內保持常量。 如果聲明了NOT NULL,那麼賦予NULL數值將導致一個執行時錯誤。 所以所有聲明為NOT NULL的變量還必須聲明一個非空的預設值。

預設值是在每次進入該塊的時候計算的。因此,如果把 now() 賦予一個類型為 timestamp 的變量會令變量擁有函數實際調用的時間,而不是函數預編譯的時間。

例子︰

quantity integer DEFAULT 32;
url varchar := 'http://mysite.com';
user_id CONSTANT integer := 10;

35.4.1. 函數參數的別名

傳遞給函數的參數都是用 $1$2,等等這樣的標識符。 為了增加可讀性,我們可以為 $n 參數名聲明別名。 然後別名或者數字標識符都可以指向參數值。

有兩種建立別名的方法,比較好的是在 CREATE FUNCTION 命令裡給出參數名, 比如:

CREATE FUNCTION sales_tax(subtotal real) RETURNS real AS $$
BEGIN
    RETURN subtotal * 0.06;
END;
$$ LANGUAGE plpgsql;

另外一個方法,是 PostgreSQL 8.0 以前的唯一的方法, 是明確地聲明為別名,使用聲明語法

name ALIAS FOR $n;

這個風格的同一個例子看起來像下面這樣

CREATE FUNCTION sales_tax(REAL) RETURNS real AS $$
DECLARE
    subtotal ALIAS FOR $1;
BEGIN
    RETURN subtotal * 0.06;
END;
$$ LANGUAGE plpgsql;

更多例子:

CREATE FUNCTION instr(varchar,integer) RETURNS integer AS $$
DECLARE
    v_string ALIAS FOR $1;
    index ALIAS FOR $2;
BEGIN
    -- 這裡放一些計算
END;
$$ LANGUAGE plpgsql;

CREATE FUNCTION concat_selected_fields(in_t tablename) RETURNS text AS $$
BEGIN
    RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;
END;
$$ LANGUAGE plpgsql;

如果一個 PL/pgSQL 函數的返回類型聲明為一個多態類型 (anyelement 或者 anyarray),那麼就會建立一個特殊的參數, $0。它的資料類型是函數的實際返回類型,和從實際輸入類型推導推導類型一樣 (參閱 Section 31.2.5)。 這樣就允許函數訪問它的實際返回類型,像 Section 35.4.2 裡顯示的那樣。 $0 初始化為空,並且可以被函數修改,所以,如果需要,它可以用於保存返回值, 雖然這並非必須的。$0 還可以給予一個別名。比如,這個函數可以在任何有 + 操作符的資料類型上運轉:

CREATE FUNCTION add_three_values(v1 anyelement, v2 anyelement, v3 anyelement)
RETURNS anyelement AS $$
DECLARE
    result ALIAS FOR $0;
BEGIN
    result := v1 + v2 + v3;
    RETURN result;
END;
$$ LANGUAGE plpgsql;

35.4.2. 拷貝類型

variable%TYPE

%TYPE 提供一個變量或者資料表字串的資料類型。 您可以用這個聲明將要保存資料庫數值的變量。比如,假如您在 users 資料表裡面有一個字串叫 user_id。要聲明一個和 users.user_id 類型相同的變量,您可以寫:

user_id users.user_id%TYPE;

透過使用 %TYPE,您必須知道您引用的結構的資料類型, 並且,最重要的是,如果被引用項的資料類型在將來變化了(比如:您把 user_id 的類型從 integer 改成 real),您也不需要修改您的函數定義。

%TYPE 對多態的函數特別有用,因為內部變量的資料類型可能在不同調用中是不一樣的。 我們可以透過給函數的參數或者結果佔位符附加 %TYPE 的方法來建立合適的變量。

35.4.3. 行類型

name table_name%ROWTYPE;
name composite_type_name;

一個復合類型變量叫做變量(或者row-type變量)。 這樣的一個變量可以保存一次SELECT或者 FOR命令結果的完整一行,只要命令的字串集匹配該變量聲明的類型。 行數值的獨立的字串是使用常用的點資料表示法訪問的,比如 rowvar.field

一個行變量可以聲明為和一個現有的資料表或者視圖的行類型相同,方法是使用 table_name%ROWTYPE 資料表示法; 或者您也可以聲明它的類型是一個復合類型的名字。(因為每個資料表都有一個相關聯的同名資料類型, 在 PostgreSQL 裡實在是無所謂您寫不寫 %ROWTYPE。但是有 %ROWTYPE 的形式移植性更好。)

函數的參數可以是復合類型(資料表的完整行)。這個時候, 對應的標識符 $n 將是一個行變量,並且可以從中選取字串,比如 $1.user_id

在一個行類型的變量中,只可以訪問用戶定義的資料表中行的屬性, 不包括 OID 或者其他系統屬性(因為該行可能來自一個視圖)。 該行類型的資料域繼承資料表中象 char(n) 這種類型字串的尺寸和精度。

這裡是一個使用復合類型的例子:

CREATE FUNCTION merge_fields(t_row tablename) RETURNS text AS $$
DECLARE
    t2_row table2name%ROWTYPE;
BEGIN
    SELECT * INTO t2_row FROM table2name WHERE ... ;
    RETURN t_row.f1 || t2_row.f3 || t_row.f5 || t2_row.f7;
END;
$$ LANGUAGE plpgsql;

SELECT merge_fields(t.*) FROM tablename t WHERE ... ;

35.4.4. 記錄類型

name RECORD;

紀錄變量類似行類型變量,但是它們沒有預定義的結構。 它們在SELECT或者FOR命令中獲取實際的行結構。 一個行變量的子結構可以在每次賦值的時候改變。 這樣做的一個結果是:在一個記錄變量被賦予數值之前,它沒有子結構, 並且任何對其中的資料域進行訪問的企圖都將產生一個執行時錯誤。

請注意 RECORD 不是真正的資料類型,只是一個佔位符。 我們還應該意識到在把一個 PL/pgSQL 函數聲明為返回record類型的時候, 它和一個記錄變量的概念並不完全相同,即使這個函數可能使用一個記錄變量保存它的結果也如此。 在兩種情況下,在書寫函數的時候,實際的行結構都是不知道的,但是對於返回 record 的函數來說, 實際的結構是在調用它的查詢被分析的時候決定的,而行變量可以在執行中改變其行結構。

35.4.5. RENAME

RENAME oldname TO newname;

您可以用 RENAME 聲明修改一個變量,記錄或者行的名字。 如果 NEW 或者 OLD 在個觸發器過程裡被另外一個名字引用, 那麼這個東西就很有用。又見 ALIAS

例子︰

RENAME id TO user_id;
RENAME this_var TO that_var;

注意: RENAMEPostgreSQL7.3 裡好像有問題。修補這個毛病的優先級比較低, 因為 ALIAS 覆蓋了大多數 RENAME 的實際用途。