这个帖子转自http://bbs.,把两个帖子合在一起了 很多内容是网上查的资料,我只是整理下,有遗漏的地方,欢迎补充 首先用工具(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 ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() --3 创建函数,加上 for update 属性 CREATE or replace FUNCTION fun_employee_for_update() RETURNS INTEGER AS ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() --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 另外: oracle中 %rowcount pg 可以用 GET DIAGNOSTICS integer_var = ROW_COUNT; oracle 中我们调试过程时常用 output.putline 去输出一些变量的值 在pg 中 可以用 RAISE NOTICE 'i IS %', i; 去输出你想输出的变量。 |
|