将oracle迁移到postgre数据库

首先可以尝试使用工具(Ora2pg)自动转换
用这个工具可以将一些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有全局变量的情况修改起来比较麻烦,我们是用临时表传递的。
13、cursor的属性
        %FOUND → found
        %NOTFOUND → not found
        %ISOPEN → pgsql不支持
        %ROWCOUNT → pgsql不支持
14、COMMIT,ROLLBACK;SAVEPOINT → pgsql不支持
15、Oracle的系统包,例如 DBMS_OUTPUT,DBMS_SQL,UTIL_FILE,UTIL_MAIL → pgsql不支持
16、异常处理方法不同
17、trigger的语法不同
18、日期的加减计算语法不同。


另外关于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、创建表和初始数据

--1 创建表和初始数据
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

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

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

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

2、创建函数,不带 for update 属性

--2 创建函数,不带 for update 属性
CREATE or replace FUNCTION fun_employee() 
RETURNS INTEGER AS DECLARE update flag INTEGER;
    recref cursor;
BEGIN 
    update flag:=0;
    for recin(select ∗ from employee)
    loop update employee set depno=3;
    update flag:=update flag+1;
    RAISENOTICE′The update flag is end loop;
    return 0;
END;
DECLARE update flag INTEGER;
    recref cursor;
BEGIN     update flag:=0;
    for recin(select ∗ from employee)
    loop update employee set depno=3;
    update flag:= update flag+1;
    RAISENOTICE′The update flag is end loop;
    return 0;
END;

LANGUAGE 'plpgsql';




--3 创建函数,加上 for update 属性
CREATE or replace FUNCTION fun_employee_for_update() RETURNS INTEGER AS

DECLAREupdateflagINTEGER;recrefcursor;BEGINupdateflag:=0;forrecin(select∗fromemployeeforupdate)loopupdateemployeesetdepno=3;updateflag:=updateflag+1;RAISENOTICE′Theupdateflagisendloop;return0;END;DECLAREupdateflagINTEGER;recrefcursor;BEGINupdateflag:=0;forrecin(select∗fromemployeeforupdate)loopupdateemployeesetdepno=3;updateflag:=updateflag+1;RAISENOTICE′Theupdateflagisendloop;return0;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

DECLAREupdateflagINTEGER;curcursorisselect∗fromemployeeforupdate;recemployeeBEGINupdateflag:=0;forrecincurloopupdateemployeesetdepno=3;updateflag:=updateflag+1;RAISENOTICE′Theupdateflagisendloop;return0;END;DECLAREupdateflagINTEGER;curcursorisselect∗fromemployeeforupdate;recemployeeBEGINupdateflag:=0;forrecincurloopupdateemployeesetdepno=3;updateflag:=updateflag+1;RAISENOTICE′Theupdateflagisendloop;return0;END;

LANGUAGE 'plpgsql';


另外:
oracle中 %rowcount pg 可以用 GET DIAGNOSTICS integer_var = ROW_COUNT;
oracle 中我们调试过程时常用 output.putline 去输出一些变量的值 在pg 中 可以用 RAISE NOTICE 'i IS %', i; 去输出你想输出的变量。

你可能感兴趣的:(数据库,数据库,迁移,Oracle,postgre)