摘要:在當前GaussDB(DWS)的能力中主要支持兩種過程化SQL語言,即基於PostgreSQL的PL/pgSQL以及基於Oracle的PL/SQL。本篇文章咱們經過匿名塊,函數,存儲過程向你們介紹一下GaussDB(DWS)對於過程化SQL語言的基本能力。
本文分享自華爲雲社區《GaussDB(DWS) SQL進階之PLSQL(一)-匿名塊、函數和存儲過程》,原文做者:xxxsql123 。sql
GaussDB(DWS)中的PLSQL語言,是一種可載入的過程語言,其建立的函數能夠被用在任何可使用內建函數的地方。例如,能夠建立複雜條件的計算函數而且後面用它們來定義操做符或把它們用於索引表達式。數據庫
SQL被大多數數據庫用做查詢語言。它是可移植的而且容易學習。可是每個SQL語句必須由數據庫服務器單獨執行。express
這意味着客戶端應用必須發送每個查詢到數據庫服務器、等待它被處理、接收並處理結果、作一些計算,而後發送更多查詢給服務器。若是客戶端和數據庫服務器不在同一臺機器上,全部這些會引發進程間通訊而且將帶來網絡負擔。segmentfault
經過PLSQL語言,能夠將一整塊計算和一系列查詢分組在數據庫服務器內部,這樣就有了一種過程語言的能力而且使SQL更易用,同時能節省的客戶端/服務器通訊開銷。服務器
在當前GaussDB(DWS)的能力中主要支持兩種過程化SQL語言,即基於PostgreSQL的PL/pgSQL以及基於Oracle的PL/SQL。本篇文章咱們經過匿名塊,函數,存儲過程向你們介紹一下GaussDB(DWS)對於過程化SQL語言的基本能力。微信
匿名塊(Anonymous Block)通常用於不頻繁執行的腳本或不重複進行的活動。它們在一個會話中執行,並不被存儲。網絡
在GaussDB(DWS)中經過針對PostgreSQL和Oracle風格的整合,目前支持如下兩種方式調用,對於Oracle遷移到GaussDB(DWS)的存儲過程有了很好的兼容性支持。函數
語法格式:oop
[DECLARE [declare_statements]] BEGIN execution_statements END; /
執行用例:post
postgres=# DECLARE postgres-# my_var VARCHAR2(30); postgres-# BEGIN postgres$# my_var :='world'; postgres$# dbms_output.put_line('hello '||my_var); postgres$# END; postgres$# / hello world ANONYMOUS BLOCK EXECUTE
語法格式:
DO [ LANGUAGE lang_name ] code;
執行用例:
postgres=# DO $$DECLARE postgres$# my_var char(30); postgres$# BEGIN postgres$# my_var :='world'; postgres$# raise info 'hello %' , my_var; postgres$# END$$; INFO: hello world ANONYMOUS BLOCK EXECUTE
這時細心的小夥伴們就會發現,GaussDB(DWS)不只支持了Oracle的PL/SQL的兼容性支持,對於Oracle高級包中的dbms_output.put_line函數也作了支持。因此咱們也能夠將兩個風格混用,發現也是支持的。(^-^)V
postgres=# DO $$DECLARE postgres$# my_var VARCHAR2(30); postgres$# BEGIN postgres$# my_var :='world'; postgres$# dbms_output.put_line('hello '||my_var); postgres$# END$$; hello world ANONYMOUS BLOCK EXECUTE
既然匿名塊GaussDB支持了Oracle和PostgreSQL兩種風格的建立,函數固然也會支持兩種啦。
下面咱們一塊兒來看看具體的使用吧!(。ì _ í。)
語法格式:
CREATE [ OR REPLACE ] FUNCTION function_name ( [ { argname [ argmode ] argtype [ { DEFAULT | := | = } expression ]} [, ...] ] ) [ RETURNS rettype [ DETERMINISTIC ] | RETURNS TABLE ( { column_name column_type } [, ...] )] LANGUAGE lang_name [ {IMMUTABLE | STABLE | VOLATILE } | {SHIPPABLE | NOT SHIPPABLE} | WINDOW | [ NOT ] LEAKPROOF | {CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT } | {[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | AUTHID DEFINER | AUTHID CURRENT_USER} | {fenced | not fenced} | {PACKAGE} | COST execution_cost | ROWS result_rows | SET configuration_parameter { {TO | =} value | FROM CURRENT }} ][...] { AS 'definition' | AS 'obj_file', 'link_symbol' }
執行用例:
定義函數爲SQL查詢的形式:
postgres=# CREATE FUNCTION func_add_sql(integer, integer) RETURNS integer postgres-# AS 'select $1 + $2;' postgres-# LANGUAGE SQL postgres-# IMMUTABLE postgres-# RETURNS NULL ON NULL INPUT; CREATE FUNCTION postgres=# select func_add_sql(1, 2); func_add_sql -------------- 3 (1 row)
定義函數爲plpgsql語言的形式:
postgres=# CREATE OR REPLACE FUNCTION func_add_sql2(a integer, b integer) RETURNS integer AS $$ postgres$# BEGIN postgres$# RETURN a + b; postgres$# END; postgres$# $$ LANGUAGE plpgsql; CREATE FUNCTION postgres=# select func_add_sql2(1, 2); func_add_sql2 --------------- 3 (1 row)
定義返回爲SETOF RECORD的函數:
postgres=# CREATE OR REPLACE FUNCTION func_add_sql3(a integer, b integer, out sum bigint, out product bigint) postgres-# returns SETOF RECORD postgres-# as $$ postgres$# begin postgres$# sum = a + b; postgres$# product = a * b; postgres$# return next; postgres$# end; postgres$# $$language plpgsql; CREATE FUNCTION postgres=# select * from func_add_sql3(1, 2); sum | product -----+--------- 3 | 2 (1 row)
語法格式:
CREATE [ OR REPLACE ] FUNCTION function_name ( [ { argname [ argmode ] argtype [ { DEFAULT | := | = } expression ] } [, ...] ] ) RETURN rettype [ DETERMINISTIC ] [ {IMMUTABLE | STABLE | VOLATILE } | {SHIPPABLE | NOT SHIPPABLE} | {PACKAGE} | {FENCED | NOT FENCED} | [ NOT ] LEAKPROOF | {CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT } | {[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | AUTHID DEFINER | AUTHID CURRENT_USER } | COST execution_cost | ROWS result_rows | SET configuration_parameter { {TO | =} value | FROM CURRENT ][...] { IS | AS } plsql_body /
執行用例:
定義爲Oracle的PL/SQL風格的函數:
實例1:
postgres=# CREATE FUNCTION func_add_sql2(a integer, b integer) RETURN integer postgres-# AS postgres$# BEGIN postgres$# RETURN a + b; postgres$# END; postgres$# / CREATE FUNCTION postgres=# call func_add_sql2(1, 2); func_add_sql2 --------------- 3 (1 row)
實例2:
postgres=# CREATE OR REPLACE FUNCTION func_add_sql3(a integer, b integer) RETURN integer postgres-# AS postgres$# sum integer; postgres$# BEGIN postgres$# sum := a + b; postgres$# return sum; postgres$# END; postgres$# / CREATE FUNCTION postgres=# call func_add_sql3(1, 2); func_add_sql3 --------------- 3 (1 row)
若想使用Oracle的PL/SQL風格定義OUT參數須要使用到存儲過程,請看下面章節。
存儲過程與函數功能基本類似,都屬於過程化SQL語言,不一樣的是存儲過程沒有返回值。
※ 須要注意的是目前GaussDB(DWS)只支持Oracle的CREATE PROCEDURE的語法支持,暫時不支持PostgreSQL的CREATE PROCEDURE語法支持。
暫不支持。
語法格式:
CREATE [ OR REPLACE ] PROCEDURE procedure_name [ ( {[ argmode ] [ argname ] argtype [ { DEFAULT | := | = } expression ]}[,...]) ] [ { IMMUTABLE | STABLE | VOLATILE } | { SHIPPABLE | NOT SHIPPABLE } | {PACKAGE} | [ NOT ] LEAKPROOF | { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT } | {[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | AUTHID DEFINER | AUTHID CURRENT_USER} | COST execution_cost | ROWS result_rows | SET configuration_parameter { [ TO | = ] value | FROM CURRENT } ][ ... ] { IS | AS } plsql_body /
執行用例:
postgres=# CREATE OR REPLACE PROCEDURE prc_add postgres-# ( postgres(# param1 IN INTEGER, postgres(# param2 IN OUT INTEGER postgres(# ) postgres-# AS postgres$# BEGIN postgres$# param2:= param1 + param2; postgres$# dbms_output.put_line('result is: '||to_char(param2)); postgres$# END; postgres$# / CREATE PROCEDURE postgres=# call prc_add(1, 2); result is: 3 param2 -------- 3 (1 row)
通過以上對GaussDB(DWS)過程化SQL語言的簡單介紹,咱們大體瞭解了在GaussDB(DWS)中匿名塊,函數,存儲過程的建立,下面將簡單介紹一下在過程化SQL語言中的一些簡單的語法介紹。
支持 = 與 := 兩種賦值符合的使用。下面兩種賦值方式都是支持的。
a = b; a := b + 1;
條件語句:
支持IF ... THEN ... END IF; IF ... THEN ... ELSE ... END IF; IF ... THEN ... ELSEIF ... THEN ... ELSE ... END IF;其中ELSEIF也能夠寫成ELSIF。
語法介紹:
-- Case 1: IF 條件表達式 THEN --表達式爲TRUE後將執行的語句 END IF; -- Case 2: IF 條件表達式 THEN --表達式爲TRUE後將執行的語句 ELSE --表達式爲FALSE後將執行的語句 END IF; -- Case 3: IF 條件表達式1 THEN --表達式1爲TRUE後將執行的語句 ELSEIF 條件表達式2 THEN --表達式2爲TRUE 後將執行的語句 ELSE --以上表達式都不爲TRUE 後將執行的語句 END IF;
示例:
postgres=# CREATE OR REPLACE PROCEDURE pro_if_then(IN i INT) postgres-# AS postgres$# BEGIN postgres$# IF i>5 AND i<10 THEN postgres$# dbms_output.put_line('This is if test.'); postgres$# ELSEIF i>10 AND i<15 THEN postgres$# dbms_output.put_line('This is elseif test.'); postgres$# ELSE postgres$# dbms_output.put_line('This is else test.'); postgres$# END IF; postgres$# END; postgres$# / CREATE PROCEDURE postgres=# call pro_if_then(1); This is else test. pro_if_then ------------- (1 row) postgres=# call pro_if_then(6); This is if test. pro_if_then ------------- (1 row) postgres=# call pro_if_then(11); This is elseif test. pro_if_then ------------- (1 row)
支持while,for, foreach的使用。循環期間也能夠適當添加循環控制語句continue, break。
語法介紹:
WHILE 條件表達式1 THEN --循環內須要執行的語句 END LOOP; FOR i IN result LOOP --循環內須要執行的語句 END LOOP; FOREACH var IN result LOOP --循環內須要執行的語句 END LOOP;
示例:
postgres=# CREATE OR REPLACE FUNCTION func_loop(a integer) RETURN integer postgres-# AS postgres$# sum integer; postgres$# var integer; postgres$# BEGIN postgres$# sum := a; postgres$# WHILE sum < 10 LOOP postgres$# sum := sum + 1; postgres$# END LOOP; postgres$# postgres$# RAISE INFO 'current sum: %', sum; postgres$# FOR i IN 1..10 LOOP postgres$# sum := sum + i; postgres$# END LOOP; postgres$# postgres$# RAISE INFO 'current sum: %', sum; postgres$# FOREACH var IN ARRAY ARRAY[1, 2, 3, 4] LOOP postgres$# sum := sum + var; postgres$# END LOOP; postgres$# postgres$# RETURN sum; postgres$# END; postgres$# / CREATE FUNCTION postgres=# call func_loop(1); INFO: current sum: 10 INFO: current sum: 65 func_loop ----------- 75 (1 row)
支持goto語法的使用。
語法介紹:
GOTO LABEL; --若干語句 <<label>>
示例:
postgres=# CREATE OR REPLACE FUNCTION goto_while_goto() postgres-# RETURNS TEXT postgres-# AS $$ postgres$# DECLARE postgres$# v0 INT; postgres$# v1 INT; postgres$# v2 INT; postgres$# test_result TEXT; postgres$# BEGIN postgres$# v0 := 1; postgres$# v1 := 10; postgres$# v2 := 100; postgres$# test_result = ''; postgres$# WHILE v1 < 100 LOOP postgres$# v1 := v1+1; postgres$# v2 := v2+1; postgres$# IF v1 > 25 THEN postgres$# GOTO pos1; postgres$# END IF; postgres$# END LOOP; postgres$# postgres$# <<pos1>> postgres$# /* OUTPUT RESULT */ postgres$# test_result := 'GOTO_base=>' || postgres$# ' v0: (' || v0 || ') ' || postgres$# ' v1: (' || v1 || ') ' || postgres$# ' v2: (' || v2 || ') '; postgres$# RETURN test_result; postgres$# END; postgres$# $$ postgres-# LANGUAGE 'plpgsql'; CREATE FUNCTION postgres=# postgres=# SELECT goto_while_goto(); goto_while_goto ------------------------------------------- GOTO_base=> v0: (1) v1: (26) v2: (116) (1 row)
語法介紹:
[<<label>>] [DECLARE declarations] BEGIN statements EXCEPTION WHEN condition [OR condition ...] THEN handler_statements [WHEN condition [OR condition ...] THEN handler_statements ...] END;
示例:
postgres=# CREATE TABLE mytab(id INT,firstname VARCHAR(20),lastname VARCHAR(20)) DISTRIBUTE BY hash(id); CREATE TABLE postgres=# INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones'); INSERT 0 1 postgres=# CREATE FUNCTION fun_exp() RETURNS INT postgres-# AS $$ postgres$# DECLARE postgres$# x INT :=0; postgres$# y INT; postgres$# BEGIN postgres$# UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones'; postgres$# x := x + 1; postgres$# y := x / 0; postgres$# EXCEPTION postgres$# WHEN division_by_zero THEN postgres$# RAISE NOTICE 'caught division_by_zero'; postgres$# RETURN x; postgres$# END;$$ postgres-# LANGUAGE plpgsql; CREATE FUNCTION postgres=# call fun_exp(); NOTICE: caught division_by_zero fun_exp --------- 1 (1 row) postgres=# select * from mytab; id | firstname | lastname ----+-----------+---------- | Tom | Jones (1 row) postgres=# DROP FUNCTION fun_exp(); DROP FUNCTION postgres=# DROP TABLE mytab; DROP TABLE
GaussDB(DWS)對於過程化SQL語言的支持主要在PostgreSQL與Oracle上作了兼容,同時針對Oracle的一些高級包以及一些Oracle獨有的語法也作了必定支持。在遷移Oracle或者PostgreSQL時,對於函數或存儲過程的遷移能夠減小爲了兼容致使的額外工做量。
至此已經將GaussDB(DWS)中的匿名塊,函數,存儲過程的建立以及基本使用介紹的差很少了。固然GaussDB(DWS)對於過程化SQL語言的支持不止如此,在接下來的時間裏,還將逐步向你們介紹遊標,用戶自定義類型等章節喲~
想了解GuassDB(DWS)更多信息,歡迎微信搜索「GaussDB DWS」關注微信公衆號,和您分享最新最全的PB級數倉黑科技,後臺還可獲取衆多學習資料哦~