PostgreSQL 存儲過程與函數
wangzhiqing999
PostgreSQL 存儲過程與函數
創建一個存儲過程PostgreSQL 好像沒有專門的 CREATE OR REPLACE PROCEDURE 全部都是 FUNCTION 的樣子。
對於沒有返回值的。 可以通過 RETURNS void 來實現。
要更新一個現有函數的定義,使用 CREATE OR REPLACE FUNCTION。
我們不能用這個方法修改一個函數的名字或者參數類型(如果你這麼幹,那麼你就會創建一個新的,不同的函數)。
同樣,CREATE OR REPLACE FUNCTION 也不會允許你修改一個現有函數的返回類型。
要做這些事情,你必須刪除並重新創建函數。
(如果使用 OUT 參數,那就意味着除了刪除函數,你不能修改任何 OUT 參數的類型或者名字。)
如果你刪除然後重建一個函數,新函數和舊的將是不同的實體;你就需要刪除現有引用了老函數的規則,視圖,觸發器等等。
使用 CREATE OR REPLACE FUNCTION 可以在不破壞引用該函數的對象的前提下修改函數定義。
好像沒有 print 之類的語句。
只好 把結果寫入臨時表
Test=# CREATE TABLE test_helloworld(
Test(# data varchar(30)
Test(# );
CREATE TABLE
Test=#
請注意, 定義存儲過程內使用的變量, 需要定義在 BEGIN 之前, 需要加 DECLARE 關鍵字。
多個變量之間用分號分隔。
Test=# CREATE OR REPLACE FUNCTION HelloWorld() RETURNS void AS
Test-# $$
Test$# DECLARE
Test$# testvalue1 VARCHAR(20);
Test$# testvalue2 VARCHAR(20);
Test$# BEGIN
Test$# testvalue1 := 'First Test! ';
Test$# SELECT 'Second Test !' INTO testvalue2;
Test$# INSERT INTO test_helloworld
Test$# SELECT 'Hello World' ;
Test$# INSERT INTO test_helloworld (data)
Test$# VALUES (testvalue1 || testvalue2);
Test$# END;
Test$# $$
Test-# LANGUAGE plpgsql;
CREATE FUNCTION
Test=#
Test=# SELECT HelloWorld();
helloworld
------------
(1 行記錄)
Test=# select * from test_helloworld;
data
---------------------------
Hello World
First Test! Second Test !
(2 行記錄)
Test=#
修改存儲過程
要更新一個現有函數的定義,使用 CREATE OR REPLACE FUNCTION。
我們不能用這個方法修改一個函數的名字或者參數類型(如果你這麼幹,那麼你就會創建一個新的,不同的函數)。
同樣,CREATE OR REPLACE FUNCTION 也不會允許你修改一個現有函數的返回類型。
要做這些事情,你必須刪除並重新創建函數。
(如果使用 OUT 參數,那就意味着除了刪除函數,你不能修改任何 OUT 參數的類型或者名字。)
如果你刪除然後重建一個函數,新函數和舊的將是不同的實體;你就需要刪除現有引用了老函數的規則,視圖,觸發器等等。
使用 CREATE OR REPLACE FUNCTION 可以在不破壞引用該函數的對象的前提下修改函數定義。
具體代碼略.
需要注意的一點。
刪除函數的時候, 需要傳遞完整的參數列表, 僅僅指定一個 函數的名稱, 是無法刪除的。
例如:
Test=# drop FUNCTION HelloWorld;
錯誤: 語法錯誤 在 ";" 或附近的
第1行drop FUNCTION HelloWorld;
^
Test=# drop FUNCTION HelloWorld();
DROP FUNCTION
Test=#
Test=# drop FUNCTION HelloWorld2;
錯誤: 語法錯誤 在 ";" 或附近的
第1行drop FUNCTION HelloWorld2;
^
Test=# drop FUNCTION HelloWorld2();
錯誤: 函數 helloworld2() 不存在
Test=# drop FUNCTION HelloWorld2(varchar);
DROP FUNCTION
Test=#
參數定義 單個參數
Test=# truncate table test_helloworld;
TRUNCATE TABLE
Test=# CREATE OR REPLACE FUNCTION HelloWorld1(vUserName VARCHAR) RETURNS void AS
Test-# $$
Test$# BEGIN
Test$# INSERT INTO test_helloworld
Test$# VALUES('Hello ' || vUserName);
Test$# END;
Test$# $$
Test-# LANGUAGE plpgsql;
CREATE FUNCTION
Test=#
Test=# SELECT HelloWorld1('ABC');
helloworld1
-------------
(1 行記錄)
Test=# select * from test_helloworld;
data
-----------
Hello ABC
(1 行記錄)
函數參數的別名Test=# truncate table test_helloworld;
TRUNCATE TABLE
-- 請注意這裏: 定義參數的時候, 沒有定義參數名稱, 僅僅定義了參數的數據類型
-- 然後在 定義變量的位置, 通過 vUserName ALIAS FOR $1 來爲 第一個參數, 指定一個變量名稱, 叫做 vUserName
Test=# CREATE OR REPLACE FUNCTION HelloWorld2 (varchar) RETURNS void AS
Test-# $$
Test$# DECLARE
Test$# vUserName ALIAS FOR $1;
Test$# BEGIN
Test$# INSERT INTO test_helloworld
Test$# VALUES('Hello ' || vUserName);
Test$# END;
Test$# $$
Test-# LANGUAGE plpgsql;
CREATE FUNCTION
Test=# SELECT HelloWorld2('XYZ');
helloworld2
-------------
(1 行記錄)
Test=# select * from test_helloworld;
data
-----------
Hello XYZ
(1 行記錄)
某些情況下, 希望定義參數的時候, 數據類型,與某個表中的某一列的數據類型一樣。
這樣,將來萬一業務變化, 表的數據類型變化了,不需要修改存儲過程代碼。
定義的方式,是 表名.列名%TYPECREATE TABLE test_type (test_ID INT,
test_name varchar(20)
);
Test=# CREATE OR REPLACE FUNCTION HelloWorld20 (
Test(# p_user_name test_type.test_name%TYPE Test(# ) RETURNS void ASTest-# $$
Test$# BEGIN
Test$# INSERT INTO test_type VALUES(1, p_user_name);
Test$# END;
Test$# $$
Test-# LANGUAGE plpgsql;
注意: 類型關聯 test_type.test_name%TYPE 轉換爲 character varying
CREATE FUNCTION
Test=#
Test=# select HelloWorld20('Test');
helloworld20
--------------
(1 行記錄)
Test=# select * from test_type;
test_id | test_name
---------+-----------
1 | Test
(1 行記錄)
參數定義- IN、OUT、IN OUT
Test=# truncate table test_helloworld;
TRUNCATE TABLE
Test=# CREATE OR REPLACE FUNCTION HelloWorld3 (
Test(# IN vUserName VARCHAR,
Test(# OUT vOutValue VARCHAR
Test(# ) AS
Test-# $$
Test$# BEGIN
Test$# INSERT INTO test_helloworld
Test$# VALUES('Hello ' || vUserName);
Test$# vOutValue := 'A';
Test$# END;
Test$# $$
Test-# LANGUAGE plpgsql;
CREATE FUNCTION
Test=#
Test=# SELECT HelloWorld3('ABC');
helloworld3
-------------
A
(1 行記錄)
Test=# select * from test_helloworld;
data
-----------
Hello ABC
(1 行記錄)
參數的默認值
PostgreSQL 不直接支持 參數的默認值。
但是支持 重載。
Test=# TRUNCATE TABLE test_helloworld;
TRUNCATE TABLE
Test=# CREATE OR REPLACE FUNCTION HelloWorld3(
Test(# p_user_name VARCHAR,
Test(# p_val1 VARCHAR,
Test(# p_val2 VARCHAR) RETURNS void AS
Test-# $$
Test$# BEGIN
Test$# INSERT INTO test_helloworld (data)
Test$# VALUES (p_user_name || p_val1 || p_val2);
Test$# END;
Test$# $$
Test-# LANGUAGE plpgsql;
CREATE FUNCTION
Test=#
Test=# CREATE OR REPLACE FUNCTION HelloWorld3(
Test(# p_user_name VARCHAR,
Test(# p_val1 VARCHAR) RETURNS void AS
Test-# $$
Test$# BEGIN
Test$# PERFORM HelloWorld3(p_user_name, p_val1, ' XYZ');
Test$# END;
Test$# $$
Test-# LANGUAGE plpgsql;
CREATE FUNCTION
Test=#
Test=# CREATE OR REPLACE FUNCTION HelloWorld3(
Test(# p_user_name VARCHAR) RETURNS void AS
Test-# $$
Test$# BEGIN
Test$# PERFORM HelloWorld3(p_user_name, ' OPQ ');
Test$# END;
Test$# $$
Test-# LANGUAGE plpgsql;
CREATE FUNCTION
Test=#
Test=# SELECT HelloWorld3('ABC');
helloworld3
-------------
(1 行記錄)
Test=# select * from test_helloworld;
data
--------------
ABC OPQ XYZ
(1 行記錄)
Test=#
返回結果集
簡單查詢的函數
請注意:
這裏最後寫的是 LANGUAGE SQL; 不是 LANGUAGE plpgsql;
因爲函數裏面, 沒有任何邏輯, 只有一條 SQL 語句.
CREATE OR REPLACE FUNCTION GetTestMain (int) RETURNS test_main AS $$
SELECT * FROM test_main WHERE id = $1;
$$ LANGUAGE SQL;
Test=# SELECT * FROM GetTestMain(1) AS t;
id | value
----+-------
1 | ONE
(1 行記錄)
Test=# CREATE OR REPLACE FUNCTION GetTestMain (int) RETURNS test_main AS $$
Test$# SELECT * FROM test_main WHERE id != $1;
Test$# $$ LANGUAGE SQL;
CREATE FUNCTION
Test=# SELECT * FROM GetTestMain(0) AS t;
id | value
----+-------
1 | ONE
(1 行記錄)
Test=# SELECT * FROM GetTestMain(1) AS t;
id | value
----+-------
2 | TWO
(1 行記錄)
請注意: 上面這種寫法, 如果查詢返回多行數據的情況下,這個函數僅僅會返回第一行。
Test=# CREATE OR REPLACE FUNCTION GetTestMain2(int) RETURNS setof test_main AS $$
Test$# SELECT * FROM test_main WHERE id != $1;
Test$# $$ LANGUAGE SQL;
CREATE FUNCTION
Test=#
Test=# SELECT * FROM GetTestMain2(1) AS t;
id | value
----+-------
2 | TWO
4 | FOUR
(2 行記錄)
通過定義 RETURNS setof ... 使得函數能過返回多行記錄.
假如業務邏輯比較複雜,無法簡單 SQL 處理的情況下
需要使用 RETURN NEXT ... 來把當前行數據,加入結果集.
使用 RETURN; 把整個結果集返回.
Test=# CREATE OR REPLACE FUNCTION GetTestMain3(int)
Test-# RETURNS SETOF test_main AS
Test-# $$
Test$# DECLARE
Test$# v_test_main_data test_main%ROWTYPE;
Test$# BEGIN
Test$# FOR v_test_main_data IN SELECT * FROM test_main LOOP
Test$# IF v_test_main_data.id = $1 THEN
Test$# -- 模擬一點邏輯操作.
Test$# CONTINUE;
Test$# END IF;
Test$# -- 把當前行數據,加入結果集.
Test$# RETURN NEXT v_test_main_data;
Test$# END LOOP;
Test$# -- 把整個結果集返回.
Test$# RETURN;
Test$# END;
Test$# $$ LANGUAGE plpgsql;
CREATE FUNCTION
Test=# SELECT * FROM GetTestMain3(1) AS t;
id | value
----+-------
2 | TWO
4 | FOUR
(2 行記錄)
普通返回的函數
Test=# CREATE OR REPLACE FUNCTION HelloWorld4() RETURNS varchar AS
Test-# $$
Test$# BEGIN
Test$# RETURN 'Hello World!';
Test$# END;
Test$# $$
Test-# LANGUAGE plpgsql;
CREATE FUNCTION
Test=#
Test=# select HelloWorld4();
helloworld4
--------------
Hello World!
(1 行記錄)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.