CREATE [OR REPLACE] FUNCTION proname(argname argtype) [returns {[SETOF] rettype|TABLE(argname argtype|like other table)}]
{language langname|IMMUTABLE|STABLE|VOLATILE}
1.CREATE OR REPLACE FUNCTION不允許改變已經存在的函數的返回值類型,如果要這樣做,那么需要將原函數刪除,然后重新創建新的函數。
2.任何被歸為STABLE 和VOLATILE類型的函數不能再segment上執行,因為會導致segment實例之間的數據不一致。
3.如果該函數不支持返回一個值,則使用void作為返回類型。只有OUT和INOUT參數時,RETURNS語句可以被省略。
4.SETOF修飾符表明函數會返回一個item集合, 而不是一個item。
5.IMMUTABLE|STABLE|VOLATILE該屬性會告訴查詢優化器關於函數的行為如果省略, VOLATILE 為默認值.
IMMUTABLE說明函數不能夠修改數據庫,並且對於給定相同的參數值的情況總是返回相同的結果。
STABLE 說明函數不能修改數據庫
VOLATILE 說明函數可以修改事件(event), 所以沒有做任何優化
6.CALLED ON NULL INPUT|RETURNS NULL ON NULL INPUT|STRICT
CALLED ON NULL INPUT (默認值)說明當一些參數為null時該函數會被調用。
RETURNS NULL ON NULL INPUT和 STRICT 說明函數總是返回null,
7.plpgsql 的動態語句 格式“execute <varchar變量的sql語句>”plpgsql沒有 execute [into <variable_list>] [using <variable_list>] 的寫法
8.plpgsql 不使用 游標,而是用 for 循環代替。
9.plpgsql 的異常信息 變量: sqlstate,sqlerrm。沒有sqlcode。ORACLE 的 異常信息 變量:sqlcode,sqlerrm。
10.查詢過程編譯過的 select prosrc from pg_proc where proname="存儲過程名稱"
Examples
一個簡單的加法函數:
CREATE FUNCTION add(integer, integer) RETURNS integer
AS 'select $1 + $2;'
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;
增加一個整形數的值,使用參數的名字, 使用 PL/pgSQL:
CREATE OR REPLACE FUNCTION increment(i integer) RETURNS
integer AS $$
BEGIN
RETURN i + 1;
END;
$$ LANGUAGE plpgsql;
對於一個PL/pgSQL函數,增加每次查詢時的segment主機內存:
CREATE OR REPLACE FUNCTION function_with_query() RETURNS
SETOF text AS $$
BEGIN
RETURN QUERY
EXPLAIN ANALYZE SELECT * FROM large_table;
END;
$$ LANGUAGE plpgsql
SET statement_mem='256MB';
連接 https://blog.csdn.net/jmx_bigdata/article/details/84316863
異常
create or replace function prc_test(in par1 text,in par2 numeric,in par3 integer)
returns void as $$
declare
v_msg varchar(4000);
begin
insert into table1 values(par1,par2,par3);
EXCEPTION
WHEN OTHERS THEN
v_msg := substr(SQLERRM, 1, 2000);
PERFORM my_err(ic_cendat, ic_jobid, ic_seq, v_msg);
END;
end;
$$ language plpgsql;
循環 while
CREATE OR REPLACE FUNCTION fun_gp_test_xxx_20181026(v_month int)
RETURNS INT AS
$BODY$
declare
v_num int;
v_count int;
begin
v_num := 0;
v_count := 1;
while v_count > 0 loop
v_num := v_num + 1;
select count(1) into v_count from temp_cwh_test_1106 where split_part(rate_item,';',v_num) <> '';
if v_count > 0 then
insert into temp_cwh_test_1106_02 select serv_id,usage_date,latn_id,split_part(rate_item,';',v_num) from temp_cwh_test_1106 where split_part(rate_item,';',v_num) <> ''; ---- 需要提前建好temp_cwh_test_1106_02表
end if;
end loop;
return 0;
end;
循環 for
說明: loop variable of loop over rows must be a record or row variable or list of scalar variables。
--創建 函數
drop function zzhtest.fnc_test();
create or replace function zzhtest.gnc_test()
returns varchar as $$
declare
rec record;
vv_result varchar(200);
begin
for rec in (select brand_code,brand_name from zzhtest.t_brand ) loop
insert into zzhtest.t_brand_bak values(rec.brand_code,rec.brand_name);
end loop;
vv_result := 'successful';
return vv_result;
exception
when others then
vv_result := substr(sqlstate ||':'|| sqlerrm,1,200);
end;
$$ language plpgsql;
2. for i in n1..n2 loop end loop
drop function zzhtest.fnc_test();
create or replace function zzhtest.gnc_test()
returns integer as $$
declare
vi_sum integer default 0;
begin
for i in 1..100 loop --此處i無需定義
vi_sum := vi_sum + i;
end loop;
return vi_sum;
exception
when others then
return -1;
end;
分支 if then elsif then else end if
drop function zzhtest.fnc_test(integer,integer);
create or replace function zzhtest.gnc_test(
in iv_a integer,
in iv_b integer
)
returns varchar as $$
declare
vv_result varchar(10);
begin
if iv_a = iv_b then
vv_result := iv_a ||'與'|| iv_b ||'相等';
elsif iv_a > iv_b then
vv_result := iv_a ||'大於'|| iv_b;
else
vv_result := iv_a ||'小於'|| iv_b;
end if;
return vv_result;
exception
when others then
vv_result := substr(sqlstate ||':'|| sqlerrm,1,200);
return vv_result;
end;
$$ language plpgsql;
【greenplum 的 靜態語句 和 動態語句】
drop function zzhtest.fnc_test(varchar,varchar);
create or replace function zzhtest.fnc_test(
in iv_brand_code varchar,
in iv_brand_name varchar
)
returns varchar as $$
declare vi_cnt integer;
declare vv_sql varchar(100);
declare vv_result varchar(200);
begin
--select into語句
select count(*) into vi_cnt from zzhtest.t_brand where brand_code = upper(iv_brand_code);
--greenplum子程序中沒有 execute into 的寫法
--vv_sql := ' select count(*) from zzhtest.t_brand where brand_code = upper('''||iv_brand_code||''')';
--execute vv_sql into vi_cnt;
if vi_cnt = 0 then
--insert into zzhtest.t_brand values(upper(iv_brand_code),upper(iv_brand_name)); --靜態語句
vv_sql := ' insert into zzhtest.t_brand values(upper('''||iv_brand_code||'''),upper('''||iv_brand_name||'''))';
execute vv_sql; --動態語句
else
--update zzhtest.t_brand set brand_name = upper(iv_brand_name) where brand_code = upper(iv_brand_code); -- 靜態語句
vv_sql := 'update zzhtest.t_brand set brand_name = upper('||quote_literal(iv_brand_name)||') where brand_code = upper('||quote_literal(iv_brand_code)||') ';
execute vv_sql; --動態語句
end if;
vv_result := 'successful';
return vv_result;
exception
when others then
vv_result := substr(sqlstate ||':'|| sqlerrm,1,200); --異常信息
end;
$$ language plpgsql;
指定表結構方式:
CREATE OR REPLACE FUNCTION ads.fv_repay_detail() RETURNS TABLE( product_id bigint, real_date varchar, principal_tot NUMERIC, principal NUMERIC, interest NUMERIC) AS $$ SELECT product_id, real_date, principal_tot, principal, interest from tb_repay_plan $$ LANGUAGE sql;
使用已有表的結構:
CREATE OR REPLACE FUNCTION table_name1 () RETURNS SETOF table_name1 AS $body$ SELECT * from table_name1; $body$ LANGUAGE 'sql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;