達夢6.0試用之PLSQL篇

yangtingkun發表於2010-07-19

前幾天ITPUB的熊建國主編和我聯絡,希望我能參加國產資料庫達夢的適用活動,並寫幾篇使用感受。本來最近手工的事情比較多,本打算推辭的,不過熊主編再三邀請,而且強調並非是槍手文,只要寫出真實使用感受即可。既然如此,我就本著支援國產資料庫的原則,寫幾篇試用感受。

由於本人唯一熟悉的資料庫就是Oracle,因此所有的對比都是與Oracle資料庫進行對比,在這個過程中,將盡可能避免將對Oracle資料庫的喜愛之情帶進來,爭取站在一個比較公正的位置上來進行評價。

這一篇簡單介紹一下達夢資料庫PL/SQL相關的內容。

 

 

達夢資料庫對於PL/SQL的支援也是出人意料的,基本上所有的關鍵性語法都與OraclePL/SQL沒有本質的區別。

SQL>BEGIN
2   INSERT INTO T VALUES (3, 'PL/SQL', SYSDATE);
3   END;
4   /
BEGIN
INSERT INTO T VALUES (3, 'PL/SQL', SYSDATE);
END;
1 rows affected
time used: 68.921(ms) clock tick:115154870.
SQL>BEGIN
2   EXECUTE IMMEDIATE 'TRUNCATE TABLE T';
3   END;
4   /
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE T';
END;
0 rows affected
time used: 31.029(ms) clock tick:51357350.
SQL>SELECT * FROM T;
SELECT * FROM T;

id              name            create_date
0 rows got
time used: 0.278(ms) clock tick:449080.

可以看到,不僅支援PL/SQL中包含的DML語句,而且連DDL語句都是支援的。

SQL>DECLARE
2       V_FLAG BOOLEAN;
3   BEGIN
4       FOR I IN 2 .. 100 LOOP
5               V_FLAG := TRUE;
6               FOR J IN 2 .. TRUNC(POWER(I, 0.5)) LOOP
7                       IF MOD(I,J) = 0 THEN
8                               V_FLAG := FALSE;
9                               EXIT;
10                      END IF;
11              END LOOP;
12
13              IF V_FLAG = TRUE THEN
14                      --DBMS_OUTPUT.PUT_LINE(I);
15                      NULL;
16              END IF;
17      END LOOP;
18  END;
19  /
DECLARE
        V_FLAG BOOLEAN;
BEGIN
        FOR I IN 2 .. 100 LOOP
                V_FLAG := TRUE;
                FOR J IN 2 .. TRUNC(POWER(I, 0.5)) LOOP
                        IF MOD(I,J) = 0 THEN
                                V_FLAG := FALSE;
                                EXIT;
                        END IF;
                END LOOP;

                IF V_FLAG = TRUE THEN
                        --DBMS_OUTPUT.PUT_LINE(I);
                        NULL;
                END IF;
        END LOOP;
END;
0 rows affected
time used: 108.993(ms) clock tick:181319230.

這時Oracle中計算100以內質數的一個PL/SQL過程,可以看到,除了呼叫DBMS_OUTPUT包之外,其他部分不用進行任何的修改就可以順利執行,在達夢的PL/SQL語句中,提供了PRINT語句來代替DBMS_OUTPUT包:

SQL>DECLARE
2       V_FLAG BOOLEAN;
3   BEGIN
4       FOR I IN 2 .. 100 LOOP
5               V_FLAG := TRUE;
6               FOR J IN 2 .. TRUNC(POWER(I, 0.5)) LOOP
7                       IF MOD(I,J) = 0 THEN
8                               V_FLAG := FALSE;
9                               EXIT;
10                      END IF;
11              END LOOP;
12
13              IF V_FLAG = TRUE THEN
14                      PRINT(I);
15              END IF;
16      END LOOP;
17  END;
18  /
DECLARE
        V_FLAG BOOLEAN;
BEGIN
        FOR I IN 2 .. 100 LOOP
                V_FLAG := TRUE;
                FOR J IN 2 .. TRUNC(POWER(I, 0.5)) LOOP
                        IF MOD(I,J) = 0 THEN
                                V_FLAG := FALSE;
                                EXIT;
                        END IF;
                END LOOP;

                IF V_FLAG = TRUE THEN
                        PRINT(I);
                END IF;
        END LOOP;
END;

2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
0 rows affected
time used: 29.325(ms) clock tick:48929860.

除了匿名塊外,達夢還支援PROCEDUREFUNCTIONTRIGGER

SQL>CREATE OR REPLACE PROCEDURE P_TEST AS
2   BEGIN
3   INSERT INTO T VALUES (1, 'TEST', SYSDATE);
4   COMMIT;
5   END;
6   /
CREATE OR REPLACE PROCEDURE P_TEST AS
BEGIN
INSERT INTO T VALUES (1, 'TEST', SYSDATE);
COMMIT;
END;

time used: 41.239(ms) clock tick:68574010.
SQL>SELECT * FROM T;
SELECT * FROM T;

id              name            create_date
0 rows got
time used: 0.319(ms) clock tick:520320.
SQL>BEGIN
2   P_TEST;
3   END;
4   /
BEGIN
P_TEST;
END;
1 rows affected
time used: 11.769(ms) clock tick:19487570.
SQL>SELECT * FROM T;
SELECT * FROM T;

id              name            create_date

1       1       TEST    2010-04-07
1 rows got
time used: 0.295(ms) clock tick:477140.

看一個函式的例子:

SQL>CREATE OR REPLACE FUNCTION F_TAX
2   (P_SALARY IN NUMBER, P_START IN NUMBER DEFAULT 2000)
3   RETURN NUMBER AS
4       V_SALARY NUMBER := P_SALARY - P_START;
5   BEGIN
6       IF V_SALARY <= 0 THEN
7               RETURN 0;
8       ELSIF V_SALARY <= 500 THEN
9               RETURN V_SALARY * 0.05;
10      ELSIF V_SALARY <= 2000 THEN
11              RETURN V_SALARY * 0.1 - 25;
12      ELSIF V_SALARY <= 5000 THEN
13              RETURN V_SALARY * 0.15 - 125;
14      ELSIF V_SALARY <= 20000 THEN
15              RETURN V_SALARY * 0.2 - 375;
16      ELSIF V_SALARY <= 40000 THEN
17              RETURN V_SALARY * 0.25 - 1375;
18      ELSIF V_SALARY <= 60000 THEN
19              RETURN V_SALARY * 0.3 - 3375;
20      ELSIF V_SALARY <= 80000 THEN
21              RETURN V_SALARY * 0.35 - 6375;
22      ELSIF V_SALARY <= 100000 THEN
23              RETURN V_SALARY * 0.4 - 10375;
24      ELSE
25              RETURN V_SALARY * 0.45 - 15375;
26      END IF;
27  END;
28  /
CREATE OR REPLACE FUNCTION F_TAX
(P_SALARY IN NUMBER, P_START IN NUMBER DEFAULT 2000)
RETURN NUMBER AS
        V_SALARY NUMBER := P_SALARY - P_START;
BEGIN
        IF V_SALARY <= 0 THEN
                RETURN 0;
        ELSIF V_SALARY <= 500 THEN
                RETURN V_SALARY * 0.05;
        ELSIF V_SALARY <= 2000 THEN
                RETURN V_SALARY * 0.1 - 25;
        ELSIF V_SALARY <= 5000 THEN
                RETURN V_SALARY * 0.15 - 125;
        ELSIF V_SALARY <= 20000 THEN
                RETURN V_SALARY * 0.2 - 375;
        ELSIF V_SALARY <= 40000 THEN
                RETURN V_SALARY * 0.25 - 1375;
        ELSIF V_SALARY <= 60000 THEN
                RETURN V_SALARY * 0.3 - 3375;
        ELSIF V_SALARY <= 80000 THEN
                RETURN V_SALARY * 0.35 - 6375;
        ELSIF V_SALARY <= 100000 THEN
                RETURN V_SALARY * 0.4 - 10375;
        ELSE
                RETURN V_SALARY * 0.45 - 15375;
        END IF;
END;

time used: 4.685(ms) clock tick:5683670.
SQL>SELECT F_TAX(10000) FROM T;
SELECT F_TAX(10000) FROM T;

 

1       1225
1 rows got
time used: 30.050(ms) clock tick:50174960.

這時以前寫的一個計算個人所得稅的函式,同樣沒有做任何的修改,放在達夢資料庫上就可以直接執行。

下面是一個PACKAGE的例子:

SQL>CREATE OR REPLACE PACKAGE PA_TEST AS
2       PROCEDURE P_TEST(P_IN NUMBER);
3       PROCEDURE P_TEST(P_IN VARCHAR);
4   END;
5   /
CREATE OR REPLACE PACKAGE PA_TEST AS
        PROCEDURE P_TEST(P_IN NUMBER);
        PROCEDURE P_TEST(P_IN VARCHAR);
END;

time used: 80.545(ms) clock tick:134160000.
SQL>CREATE OR REPLACE PACKAGE BODY PA_TEST AS
2       PROCEDURE P_TEST(P_IN NUMBER) AS
3       BEGIN
4               PRINT('NUMBER');
5       END;
6
7       PROCEDURE P_TEST(P_IN VARCHAR) AS
8       BEGIN
9               PRINT('VARCHAR');
10      END;
11  END;
12  /
CREATE OR REPLACE PACKAGE BODY PA_TEST AS
        PROCEDURE P_TEST(P_IN NUMBER) AS
        BEGIN
                PRINT('NUMBER');
        END;

        PROCEDURE P_TEST(P_IN VARCHAR) AS
        BEGIN
                PRINT('VARCHAR');
        END;
END;

time used: 20.445(ms) clock tick:33862040.
SQL>BEGIN
2   PA_TEST.P_TEST(1);
3   END;
4   /
BEGIN
PA_TEST.P_TEST(1);
END;

NUMBER
0 rows affected
time used: 0.552(ms) clock tick:913600.
SQL>BEGIN
2   PA_TEST.P_TEST('1');
3   END;
4   /
BEGIN
PA_TEST.P_TEST('1');
END;

VARCHAR
0 rows affected
time used: 0.441(ms) clock tick:725060.

這個例子顯示了包中過程的過載特性。

看一個觸發器的例子:

SQL>CREATE OR REPLACE TRIGGER T_TRI
2   BEFORE DELETE ON T
3   FOR EACH ROW
4   BEGIN
5   INSERT INTO T_BAK VALUES (:OLD.ID);
6   END;
7   /
CREATE OR REPLACE TRIGGER T_TRI
BEFORE DELETE ON T
FOR EACH ROW
BEGIN
INSERT INTO T_BAK VALUES (:OLD.ID);
END;

time used: 13.493(ms) clock tick:22369710.
SQL>INSERT INTO T VALUES (2, 'ABC', SYSDATE);
INSERT INTO T VALUES (2, 'ABC', SYSDATE)

1 rows affected
time used: 0.376(ms) clock tick:614380.
SQL>INSERT INTO T VALUES (3, 'TTT', NULL);
INSERT INTO T VALUES (3, 'TTT', NULL)

1 rows affected
time used: 0.497(ms) clock tick:818040.
SQL>DELETE T;
DELETE T;

3 rows affected
time used: 0.730(ms) clock tick:1203390.
SQL>SELECT * FROM T_BAK;
SELECT * FROM T_BAK;

ID

1       1

2       2

3       3
3 rows got
time used: 0.370(ms) clock tick:602660.

達夢支援這種最普通的DML的觸發器,還支援INSTEAD OF觸發器、但是並不支援基於資料庫事件的觸發器和基於資料庫錯誤的觸發器。

達夢資料庫的FETCH語句和PL/SQL的相比更加靈活一些,提供了隨機讀取的功能:

SQL>INSERT INTO T VALUES (1, 'A', NULL);
INSERT INTO T VALUES (1, 'A', NULL)

1 rows affected
time used: 0.461(ms) clock tick:757930.
SQL>INSERT INTO T VALUES (2, 'B', SYSDATE);
INSERT INTO T VALUES (2, 'B', SYSDATE)

1 rows affected
time used: 0.430(ms) clock tick:701910.
SQL>INSERT INTO T VALUES (3, 'ABC', '');
INSERT INTO T VALUES (3, 'ABC', '')

1 rows affected
time used: 0.333(ms) clock tick:540330.
SQL>DECLARE
2       V_NUM NUMBER;
3       C_CUR CURSOR;
4   BEGIN
5       OPEN C_CUR FOR 'SELECT ID FROM T';
6       FETCH LAST C_CUR INTO V_NUM;
7       PRINT(V_NUM);
8       FETCH PRIOR C_CUR INTO V_NUM;
9       PRINT(V_NUM);
10      FETCH ABSOLUTE 0 C_CUR INTO V_NUM;
11      PRINT(V_NUM);
12      CLOSE C_CUR;
13  END;
14  /
DECLARE
        V_NUM NUMBER;
        C_CUR CURSOR;
BEGIN
        OPEN C_CUR FOR 'SELECT ID FROM T';
        FETCH LAST C_CUR INTO V_NUM;
        PRINT(V_NUM);
        FETCH PRIOR C_CUR INTO V_NUM;
        PRINT(V_NUM);
        FETCH ABSOLUTE 0 C_CUR INTO V_NUM;
        PRINT(V_NUM);
        CLOSE C_CUR;
END;

3
2
1
0 rows affected
time used: 0.726(ms) clock tick:1199160.

其中FETCH語句指定ABSOLUTE的數值時,是從0開始的,這顯然是C語言的習慣。

達夢資料庫還有一個優點,無論是匿名塊還是過程,在SELECT的時候可以不指定FETCH的變數,這時會將查詢結果直接輸出到螢幕上:

SQL>BEGIN
2   SELECT * FROM T;
3   END;
4   /
BEGIN
SELECT * FROM T;
END;

id              name            create_date

1       1       A       NULL

2       2       B       2010-04-07

3       3       ABC     NULL
3 rows got
time used: 0.496(ms) clock tick:816250.

不過達夢資料庫的PL/SQL也有不足之處,比如不支援TYPE,不支援索引表、巢狀表和陣列。

由於不支援巢狀表和索引表,顯然也是不支援批次操作的,無論是批次插入和批次讀取都是達夢目前所不支援的。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-668414/,如需轉載,請註明出處,否則將追究法律責任。

相關文章