達夢6.0試用之SQL篇
前幾天ITPUB的熊建國主編和我聯絡,希望我能參加國產資料庫達夢的適用活動,並寫幾篇使用感受。本來最近手工的事情比較多,本打算推辭的,不過熊主編再三邀請,而且強調並非是槍手文,只要寫出真實使用感受即可。既然如此,我就本著支援國產資料庫的原則,寫幾篇試用感受。
由於本人唯一熟悉的資料庫就是Oracle,因此所有的對比都是與Oracle資料庫進行對比,在這個過程中,將盡可能避免將對Oracle資料庫的喜愛之情帶進來,爭取站在一個比較公正的位置上來進行評價。
這一篇簡單介紹一下達夢資料庫SQL相關的內容。
利用上一篇文章搭建的測試環境,首先登陸資料庫:
C:\dmdbms\bin>isql
isql V6.0.2.51-Build(2009.12.23)
SQL>login
server name:localhost
user name:test
password:
port:12345
dm_login time used:176.475(ms)
SQL>
首先測試DML語句,達夢資料庫支援SQL92標準,且相容Oracle8i的語法,下面測試一下:
SQL>INSERT INTO T
2 VALUES (1, 'TEST', SYSDATE);
INSERT INTO T
VALUES (1, 'TEST', SYSDATE)
1 rows affected
time used: 0.343(ms) clock tick:551330.
SQL>INSERT INTO T
2 VALUES (2, 'TEST AGAIN', TO_DATE('2010-3-31', 'YYYY-MM-DD'));
INSERT INTO T
VALUES (2, 'TEST AGAIN', TO_DATE('2010-3-31', 'YYYY-MM-DD'))
1 rows affected
time used: 0.516(ms) clock tick:848580.
SQL>UPDATE T
2 SET NAME = 'NEWNAME'
3 WHERE ID = 2;
UPDATE T
SET NAME = 'NEWNAME'
WHERE ID = 2;
1 rows affected
time used: 0.498(ms) clock tick:818000.
SQL>INSERT INTO T
2 SELECT ROWNUM + ID, NAME, CREATE_DATE
3 FROM T;
INSERT INTO T
SELECT ROWNUM + ID, NAME, CREATE_DATE
FROM T;
2 rows affected
time used: 67.481(ms) clock tick:112655890.
SQL>COMMIT;
COMMIT;
time used: 11.671(ms) clock tick:19334860.
SQL>SELECT * FROM T;
SELECT * FROM T;
id name create_date
1 1 TEST 2010-03-31
2 2 NEWNAME 2010-03-31
3 2 TEST 2010-03-31
4 4 NEWNAME 2010-03-31
4 rows got
time used: 0.385(ms) clock tick:631120.
SQL>DELETE T WHERE ID = 3;
DELETE T WHERE ID = 3;
0 rows affected
time used: 0.442(ms) clock tick:721900.
SQL>DELETE T WHERE ID = 4;
DELETE T WHERE ID = 4;
1 rows affected
time used: 0.475(ms) clock tick:780110.
SQL>SELECT * FROM T;
SELECT * FROM T;
id name create_date
1 1 TEST 2010-03-31
2 2 NEWNAME 2010-03-31
3 2 TEST 2010-03-31
3 rows got
time used: 0.321(ms) clock tick:520970.
最基本的SELECT、INSERT、UPDATE、DELETE操作沒有問題,甚至連ORACLE語法中的ROWNUM都支援。
在ISQL顯示結果中,有一個自動的行號顯示,但是列名顯示的時候沒有將這一位空出來,使得ID列跑到了行號的位置上,比較容易引起誤解。
SQL>MERGE INTO T
2 USING (SELECT ID + 1 ID, NAME, CREATE_DATE FROM T) T1
3 ON (T.ID = T1.ID)
4 WHEN MATCHED THEN UPDATE
5 SET T.NAME = T1.NAME, T.CREATE_DATE = T1.CREATE_DATE
6 WHEN NOT MATCHED THEN INSERT
7 VALUES (T1.ID, T1.NAME, T1.CREATE_DATE);
第1行: 'INTO'附近有語法錯誤
SQL>SELECT * FROM T
2 START WITH ID = 1
3 CONNECT BY PRIOR ID = ID + 1;
SELECT * FROM T
START WITH ID = 1
CONNECT BY PRIOR ID = ID + 1;
id name create_date
1 1 TEST 2010-03-31
1 rows got
time used: 54.497(ms) clock tick:90706490.
Oracle9i新增的MERGE語句果然是不支援的,而Oracle特有的樹形查詢居然是可以的,甚至連LEVEL偽列都是支援的:
SQL>SELECT T.*, LEVEL
2 FROM T
3 START WITH ID = 1
4 CONNECT BY ID = PRIOR ID + 1;
SELECT T.*, LEVEL
FROM T
START WITH ID = 1
CONNECT BY ID = PRIOR ID + 1;
id name create_date LEVEL
1 1 TEST 2010-03-31 1
2 2 NEWNAME 2010-03-31 2
3 2 TEST 2010-03-31 2
3 rows got
time used: 35.683(ms) clock tick:59512460.
下面看看對其他Oracle特有的語法支援的如何:
SQL>SELECT *
2 FROM T, T1
3 WHERE T.ID = T1.ID;
SELECT *
FROM T, T1
WHERE T.ID = T1.ID;
id name create_date ID
1 1 TEST 2010-03-31 1
1 rows got
time used: 0.521(ms) clock tick:855860.
SQL>SELECT *
2 FROM T, T1
3 WHERE T.ID = T1.ID (+);
SELECT *
FROM T, T1
WHERE T.ID = T1.ID (+);
id name create_date ID
1 1 TEST 2010-03-31 1
2 2 NEWNAME 2010-03-31 NULL
3 2 TEST 2010-03-31 NULL
3 rows got
time used: 36.644(ms) clock tick:61195700.
不但普通的連線支援,連Oracle的外連線’+’都是支援的。
SQL>SELECT *
2 FROM
3 (
4 SELECT ROWNUM RN, A.*
5 FROM
6 (
7 SELECT T.*
8 FROM T, T1
9 WHERE T.ID = T1.ID(+)
10 ORDER BY 2, 1
11 ) A
12 WHERE ROWNUM <= 5
13 )
14 WHERE RN > 1;
SELECT *
FROM
(
SELECT ROWNUM RN, A.*
FROM
(
SELECT T.*
FROM T, T1
WHERE T.ID = T1.ID(+)
ORDER BY 2, 1
) A
WHERE ROWNUM <= 5
)
WHERE RN > 1;
RN id name create_date
1 2 1 TEST 2010-03-31
2 3 2 TEST 2010-03-31
2 rows got
time used: 30.910(ms) clock tick:51615050.
Oracle的標準分頁語句是支援的,查詢子查詢語句是支援的,ORDER BY常量代替列名也是支援的。
SQL>SELECT ROW_NUMBER() OVER(ORDER BY NAME, ID DESC) RN,
2 ID,
3 NAME
4 FROM T;
第1行: '('附近有語法錯誤
顯然分析函式是不支援的,雖然分析函式在8i就出現了,不過確實屬於Oracle比較特有的技術,達夢不支援分析函式並不意外。
SQL>SELECT NAME, MAX(ID)
2 FROM T
3 GROUP BY NAME
4 HAVING COUNT(*) > 1;
SELECT NAME, MAX(ID)
FROM T
GROUP BY NAME
HAVING COUNT(*) > 1;
NAME
1 TEST 2
1 rows got
time used: 0.583(ms) clock tick:963240.
SQL>SELECT NAME, AVG(ID)
2 FROM T
3 GROUP BY ROLLUP(NAME);
SELECT NAME, AVG(ID)
FROM T
GROUP BY ROLLUP(NAME);
無效的儲存過程名 'ROLLUP' .error code = -1024
顯然聚集函式、GROUP BY語句和HAVING語句都是支援的。但是8i開始Oracle對GROUP BY提供了ROLLUP和CUBE功能,而這顯然是達夢所不支援的,既然ROLLUP和CUBE不支援,那麼對應的GROUPING等CUBE和ROLLUP專用的函式肯定也是不支援的。
SQL>SELECT T.ID, T1.ID ID1
2 FROM T, T1
3 WHERE T.ID = T1.ID (+)
4 ORDER BY 2 NULLS FIRST;
第4行: 'NULLS'附近有語法錯誤
支援ORDER BY語句,但是Oracle的NULLS LAST和NULLS FIRST語法並不支援。
SQL>SELECT ID, (SELECT ID FROM T1 WHERE T1.ID = T.ID)
2 FROM T;
SELECT ID, (SELECT ID FROM T1 WHERE T1.ID = T.ID)
FROM T;
ID
1 1 1
2 2 NULL
3 2 NULL
3 rows got
time used: 0.556(ms) clock tick:916730.
將子查詢作為查詢列的方式居然也是支援的,這是沒有想到的。
SQL>SELECT DECODE(ID, 1, 'A', 2, 'B', 'C')
2 FROM T;
SELECT DECODE(ID, 1, 'A', 2, 'B', 'C')
FROM T;
1 A
2 B
3 B
4 C
4 rows got
time used: 32.734(ms) clock tick:54721350.
SQL>SELECT CASE ID WHEN 1 THEN 'A' WHEN 2 THEN 'B' ELSE 'C' END
2 FROM T;
SELECT CASE ID WHEN 1 THEN 'A' WHEN 2 THEN 'B' ELSE 'C' END
FROM T;
1 A
2 B
3 B
4 C
4 rows got
time used: 0.439(ms) clock tick:724740.
達夢還支援DECODE函式和CASE語法。
SQL>SELECT * FROM T;
SELECT * FROM T;
id name create_date
1 1 TEST 2010-03-31
2 2 NEWNAME 2010-03-31
3 2 TEST 2010-03-31
3 rows got
time used: 0.385(ms) clock tick:630330.
SQL>DELETE T WHERE ID = 2 AND ROWNUM = 1;
DELETE T WHERE ID = 2 AND ROWNUM = 1;
1 rows affected
time used: 0.611(ms) clock tick:1004030.
SQL>ALTER TABLE T ADD PRIMARY KEY (ID);
ALTER TABLE T ADD PRIMARY KEY (ID);
time used: 14.329(ms) clock tick:23647990.
SQL>ALTER TABLE T1 ADD PRIMARY KEY (ID);
ALTER TABLE T1 ADD PRIMARY KEY (ID);
time used: 12.599(ms) clock tick:20886900.
SQL>UPDATE
2 (SELECT T.ID, T.NAME
3 FROM T, T1
4 WHERE T.ID = T1.ID)
5 SET NAME = 'A';
第2行: '('附近有語法錯誤
SQL>UPDATE T A
2 SET (NAME, CREATE_DATE) =
3 (SELECT NAME, CREATE_DATE FROM T WHERE ID = A.ID);
第3行: 'SELECT'附近有語法錯誤
最後測試了一下UPDATE子查詢方式,顯然這也是達夢資料庫所不支援的,不過這種語法在Oracle8i中已經出現了。另一種透過子查詢同時更新多個列的寫法也是不支援的。
SQL>login
server name:localhost
user name:sysdba
password:
port:12345
dm_login time used:43.856(ms)
SQL>select * from dual;
select * from dual;
SYSDUAL_COL
1 1
1 rows got
time used: 40.933(ms) clock tick:68373830.
達夢為了相容Oracle還特意構造了一個DUAL表。雖然欄位名稱以及記錄的值和Oracle並不相同,但是無論是欄位名還是記錄的值都是不重要的,重要的是表中只有一個欄位且只有一條記錄。
簡單總結一下,達夢資料庫在文件中說已經支援Oracle8i的語法,當時看到這種說明心裡不以為然,要知道Oracle有很多語法是SQL92標準所不支援的,比如查詢子查詢、外連線、樹形查詢等等。
但是測試的結果確實出乎意料,進行了眾多的測試,既然只有寥寥幾種寫法是達夢不支援的,其中還要去掉MERGE語句,因為這是9i才引入的新特性。
除了支援SQL92語法,以及一些常見的語法外,達夢還支援下列Oracle特有的語法:包括樹形查詢、外連線、ROWNUM偽列、LEVEL偽列、DUAL表、標準分頁查詢、甚至包括子查詢作為查詢列。
其中達夢對於樹形查詢的支援比較出乎意料,不僅支援LEVEL偽列,還支援CONNECT_IS_LEAF和CONNECT_IS_CYCLE偽列,還支援CONNECT BY NOCYCLE語句,以及CONNECT_BY_ROOT操作、SYS_CONNECT_BY_PATH函式。雖然達夢中所有樹形查詢的語法並沒有超過Oracle中的語法,但是這些偽列、函式和操作已經遠遠超過8i中Oracle的語法了,已經完全可以支援Oracle10g中樹形查詢的語法和功能了。
而在不支援的特性包括分析函式、ROLLUP和CUBE相關的GROUP BY語句、ORDER BY語句中的NULLS FIRST或NULLS LAST語句、UPDATE或DELETE子查詢語句。其中分析函式不支援再正常不過,這是Oracle提供的一個獨特的強大工具,能在記錄行級進行排序、分割槽等複雜的操作。而GROUP BY的ROLLUP和CUBE的實現應該不算太複雜,不過畢竟這部分更多的是用在資料倉儲中,在OLTP環境下很少可以用到,不支援也不會有多大的影響。而ORDER BY中的NULLS FIRST和NULLS LAST語句不支援就不太應該了,這應該是經常會使用的功能,而且實現起來應該也很容易,懷疑是被遺漏的功能。至於UPDATE或DELETE子查詢,這也是Oracle非常獨特的寫法,其中還涉及鍵值保留表的概念,因此不支援也是在情理之中。但是對於根據查詢結果同時更新多個列的情況還是比較常見的,這種寫法不但簡單,而且可以避免子查詢執行多次,這種UPDATE方式還是應該支援的。
從目前看,將8i的SQL的語句遷移到達夢資料庫上而不做修改還是可行的,九成以上的功能都已經實現了。不過在Oracle的9/10/11版本中,又增加了大量的新的語法,比如MERGE、INSERT ALL、WITH、AS OF、MODEL等等,如果達夢的新版本想要相容Oracle新版本中的語法,還是有不少難度的。
最後看看達夢中特有的寫法,說是特有隻是針對Oracle而言,這種語法早在SQLSERVER中就存在了:
SQL>SELECT TOP 2 *
2 FROM T
3 ORDER BY ID;
SELECT TOP 2 *
FROM T
ORDER BY ID;
id name create_date
1 1 TEST 2010-03-31
2 2 TEST 2010-03-31
2 rows got
time used: 31.185(ms) clock tick:52131540.
SQL>SELECT * FROM T
2 LIMIT 2 OFFSET 1;
SELECT * FROM T
LIMIT 2 OFFSET 1;
id name create_date
1 2 NEWNAME 2010-03-31
2 2 TEST 2010-03-31
2 rows got
time used: 0.469(ms) clock tick:772680.
前一個是獲取前N條記錄的方法,相當於Oracle標準分頁方式,不過語法要比標準分頁簡單得多。後面一個語句是在結果集中獲取指定位置開始的N條記錄。
在Oracle中可以透過ROWNUM或分析函式實現同樣的功能,不過語句要複雜一些。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-668275/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 達夢6.0試用之PLSQL篇SQL
- 達夢6.0試用之架構篇架構
- 達夢6.0試用之資料字典
- 達夢6.0試用之測試環境搭建
- 達夢6.0試用之資料庫物件資料庫物件
- 達夢6.0試用之資料型別資料型別
- 達夢6.0試用之併發和鎖機制
- 達夢6.0 for Windows安裝Windows
- 達夢SQL優化方法statSQL優化
- 達夢資料庫之初步測試資料庫
- 達夢SQL優化-回表BLKUP2SQL優化
- 達夢SQL優化利器-ET使用方法SQL優化
- 達夢資料庫必知必會-DCA篇資料庫
- 達夢DIsqlSQL
- 記一次處理達夢慢SQL問題SQL
- 測試學習SQL篇SQL
- 達夢安裝
- 達夢資料庫SQL執行計劃檢視方法資料庫SQL
- 【達夢】Docker安裝達夢資料庫 dm8Docker資料庫
- git使用之idea篇GitIdea
- 達夢遷移工具之MySQL資料庫遷移到達夢MySql資料庫
- 達夢使用聯機SQL執行表空間還原(二)SQL
- Asp之IIS 6.0搭建篇
- Google BERT中文應用之《紅樓夢》對話人物提取Go
- 達夢資料庫獲取SQL真實的執行計劃資料庫SQL
- DBeave如何連線達夢資料庫,設定達夢驅動,真酷資料庫
- 達夢DMDSC叢集搭建
- 達夢資料庫DM8共享叢集測試記錄資料庫
- 達夢資料庫DM8主備叢集測試記錄資料庫
- 達夢資料庫開發資料庫
- 初識達夢資料庫資料庫
- 達夢資料庫學習資料庫
- 達夢資料庫安裝資料庫
- 達夢資料庫SQL跟蹤日誌詳細介紹及配置方法資料庫SQL
- Android ADB使用之詳細篇Android
- 達夢資料庫基礎知識(三)達夢資料庫記憶體結構資料庫記憶體
- 達夢dmfldr資料快速載入
- 達夢dmfldr載入大欄位