oracle遷移到pg問題整理__oracle

來源:互聯網
上載者:User
這個文章轉自http://bbs.pgsqldb.com,把兩個文章合在一起了

很多內容是網上查的資料,我只是整理下,有遺漏的地方,歡迎補充
首先用工具(Ora2pg)自動轉換
由於這個項目背景程式量很大,預存程序+觸發器大約有15萬行代碼。
用這個工具可以將一些oracle與pgsql的文法差異自動處理下,但不是全部,剩下的需要手工修改。

ORACLE文法 → PostgreSQL文法
1、VARCHAR2 → varchar
2、DATE → timestamp
3、SYSDATE → localtimestamp
4、Oracle中''和NULL是相同的,但pgsql是不同的,所以需要將''修改成NULL
5、字串串連符 ||
Oracle: 'a'||null 結果是'a'
pgsql: 'a'||null 結果是null
所以用concat()函數替代
6、trunc(時間) → date_trunc()
7、to_char, to_number, to_date pgsql都需要指定格式
8、DECODE → case
9、NVL → coalesce()
10、外串連(+) → left(right) join
11、GOTO語句 → pgsql不支援
12、pgsql不支援procedure和package,都需要改寫成function
當package有全域變數的情況修改起來比較麻煩,我們是用暫存資料表傳遞的。
14、COMMIT,ROLLBACK;SAVEPOINT → pgsql不支援
15、Oracle的系統包,例如 DBMS_OUTPUT,DBMS_SQL,UTIL_FILE,UTIL_MAIL → pgsql不支援
16、異常處理方法不同
17、trigger的文法不同
18、日期的加減計算文法不同。

13、cursor的屬性
%FOUND → found
%NOTFOUND → not found
%ISOPEN → pgsql不支援
%ROWCOUNT → pgsql不支援
另外關於cursor還發現了其他差異,見下面:


13.1、pgsql中cursor名是全域的

例如函數A和函數B有一個相同名字的cursor,當A開啟這個cursor,然後調用B,當B再開啟同名的cursor時,會拋出異常。
這個問題在oracle中不會出現。
解決辦法:用隱式聲明定義cursor,或者保證所有的程式中cursor名唯一。

13.2、pgsql中使用for update 的cursor,loop迴圈次數很可能被改變

例如這樣一段代碼

for rec in (select * from employee for update) loop
update employee set dep_no = 'test';
end loop;

按通常的理解,如果employee中有100條記錄,這個迴圈就會執行100次,
但pgsql只會執行1次,因為一個update語句會把所有的記錄都更新了,好像與鎖有關,
如果把 for update 去掉,就會執行100次。

這個和cursor的聲明及使用方式有關,見下面實踐:
測試了加上 " for update " 和不加的情況,測試的結果都是要更新遊標結果集的次數,

實驗如下:


--1 建立表和初始資料
skytf=> create table employee(id serial,emp_name varchar(32),dep_no int4);
NOTICE: CREATE TABLE will create implicit sequence "employee_id_seq" for serial column "employee.id"
CREATE TABLE

skytf=> insert into employee (emp_name,dep_no) select generate_series(1,3)||'a',1;
INSERT 0 3

skytf=> insert into employee (emp_name,dep_no) select generate_series(4,10)||'b',2;
INSERT 0 7

skytf=> select * From employee;
id | emp_name | dep_no
----+----------+--------
1 | 1a | 1
2 | 2a | 1
3 | 3a | 1
4 | 4b | 2
5 | 5b | 2
6 | 6b | 2
7 | 7b | 2
8 | 8b | 2
9 | 9b | 2
10 | 10b | 2
(10 rows)


--2 建立函數,不帶 for update 屬性
CREATE or replace FUNCTION fun_employee() RETURNS INTEGER AS $$
DECLARE
update_flag INTEGER ;
rec refcursor;
BEGIN

update_flag :=0;

for rec in (select * from employee ) loop
update employee set dep_no = 3;
update_flag:=update_flag+1;

RAISE NOTICE ' The update_flag is %', update_flag;
end loop;
return 0;
END;
$$ LANGUAGE 'plpgsql';


--3 建立函數,加上 for update 屬性
CREATE or replace FUNCTION fun_employee_for_update() RETURNS INTEGER AS $$
DECLARE
update_flag INTEGER ;
rec refcursor;
BEGIN

update_flag :=0;

for rec in (select * from employee for update ) loop
update employee set dep_no = 3;
update_flag:=update_flag+1;

RAISE NOTICE ' The update_flag is %', update_flag;
end loop;
return 0;
END;
$$ LANGUAGE 'plpgsql';


--4 測試 fun_employee()
skytf=> select fun_employee();
NOTICE: The update_flag is 1
NOTICE: The update_flag is 2
NOTICE: The update_flag is 3
NOTICE: The update_flag is 4
NOTICE: The update_flag is 5
NOTICE: The update_flag is 6
NOTICE: The update_flag is 7
NOTICE: The update_flag is 8
NOTICE: The update_flag is 9
NOTICE: The update_flag is 10
fun_employee
--------------
0
(1 row)


--5 測試 fun_employee_for_update()
skytf=> select fun_employee_for_update();
NOTICE: The update_flag is 1
NOTICE: The update_flag is 2
NOTICE: The update_flag is 3
NOTICE: The update_flag is 4
NOTICE: The update_flag is 5
NOTICE: The update_flag is 6
NOTICE: The update_flag is 7
NOTICE: The update_flag is 8
NOTICE: The update_flag is 9
NOTICE: The update_flag is 10
fun_employee_for_update
-------------------------
0
(1 row)

備忘:根據測試結果輸出,兩個函數都執行了 10 次 update 語句。


--6
把什麼的函數改為如下聲明的cursor,只執行一次

CREATE or replace FUNCTION fun_employee_for_update() RETURNS INTEGER AS $$
DECLARE
update_flag INTEGER;
cur cursor is select * from employee for update;
rec employee%rowtype;
BEGIN

update_flag :=0;

for rec in cur loop
update employee set dep_no = 3;
update_flag:=update_flag+1;

RAISE NOTICE ' The update_flag is %', update_flag;
end loop;
return 0;
END;
$$ LANGUAGE 'plpgsql';


另外:
oracle中 %rowcount pg 可以用 GET DIAGNOSTICS integer_var = ROW_COUNT;
oracle 中我們調試過程時常用 output.putline 去輸出一些變數的值 在pg 中 可以用 RAISE NOTICE 'i IS %', i; 去輸出你想輸出的變數。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.