探索GaussDB(DWS)的過程化SQL語言能力

摘要:在當前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)的存儲過程有了很好的兼容性支持。函數

√ Oracle風格-以反斜槓結尾:

語法格式: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

√ PostgreSQL風格-以DO開頭,匿名塊用包起來:

語法格式:

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兩種風格的建立,函數固然也會支持兩種啦。

下面咱們一塊兒來看看具體的使用吧!(。ì _ í。)

√ 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)

√ Oracle風格:

語法格式:

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語法支持。

× PostgreSQL風格:

暫不支持。

√ Oracle風格:

語法格式:

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語法的使用。

語法介紹:

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級數倉黑科技,後臺還可獲取衆多學習資料哦~

點擊關注,第一時間瞭解華爲雲新鮮技術~

相關文章
相關標籤/搜索