oracle库迁移Postgres库

最近项目上要求oracle数据库迁移到pg库上去,这是本人在迁移过程中遇到的问题,记录一下,可能不全,没有的可以去pg官网查看或寻找,如果有问题还望大家多多指正。

Postgres库中文官网地址

1.日期截取 trunc()

  • oracle — trunc()

  • Postgres — date_trunc(field,source [time_zone ])

    field 的有效值(常用的)为year,month,day,hour,minute,week(截取到这周的周一)。

    source指的是类型timestamp,timestamp with time zone,interval

--oracle
select trunc(sysdate,'mm') from dual;
--对应pg
select date_trunc('month',now()::TIMESTAMP(0));

--oracle
select trunc(sysdate) from dual;
--对应pg
select date_trunc('day',now()::TIMESTAMP(0));

--pg库其他举例
SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40');
Result:2001-01-01 00:00:00
SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40+00');
Result: 2001-02-16 00:00:00-05
SELECT date_trunc('hour', INTERVAL '3 days 02:47:33');
Result: 3 days 02:00:00

如果仅是截取数字,用法跟oracle一样

2. to_date()

--oracle
select to_date('2023-04-25 23:59:59','yyyy-mm-dd hh24:mi:ss') data from dual;
Result:2023/4/25 23:59:59
--pg
select to_date('2023-04-25 23:59:59','yyyy-mm-dd hh24:mi:ss')
Result:2023/4/25  

oracle的to_date()不等价于pg库的to_date(),在PostgreSQL 中 to_date()虽然是将字符串转换成日期, 但是 仅仅是年月日部分

oracle的to_date()等价于 pg库的to_timestamp() (出来后会带着时区,要想去除时区可以在后边加上 to_timestamp()::TIMESTAMP(0) )

3.substr() 截取

  • oracle

    oracle的substr()函数下标截取从0和1开始都行

  • pg

    pg的substr()函数下标截取只能从1开始,如果是0的话,相当于从-1开始。

--oracle
select substr('123456789',0,1) from dual;
Result:1
select substr('123456789',1,1) from dual;
Result:1
    
-pg
select substr('123456789',1,1);
Result:1   

4.当前时间 sysdate

--oracle
select sysdate from dual;
--pg 格式化时区
select now()::TIMESTAMP(0);
--或者 不格式化时区
select now()/current_timestamp;

--其他
--pg 不带时分秒的当前日期
select current_date;

5. decode()

oracle中decode函数,在pg中用case when … then … else … end 代替。

用法与oracle的case when 一样。

6.nvl()

oracle 中的nvl()等价于pg库中的coalesce()。

7. update 更新操作

--pg库中update操作set 后边的字段不能加表的别名
update 表名 a set a.字段 = 'test' where a.字段 = 'test';
--上述这样修改是错的,set后边不允许加表的别名,where后边可以。改成下边这样可以
update 表名 a set 字段 = 'test' where a.字段 = 'test';

8.oracle->pg库字段对比

  • varchar2() -> varchar()
  • number -> numeric/int
  • clob -> text/bytea
  • blob -> bytea
  • date -> timestamp

pg库中date格式不带时分秒

9.递归

oracle 中的递归一般是用start with … connect by prior … 或者用 with 递归。

pg库中的递归用 with RECURSIVE ,用法与oracle的with递归一样

--举例
create table t_test 
(
    num numeric,
    p_num numeric
);
insert into t_test(num,p_num) values(1,0);
insert into t_test(num,p_num) values(2,1);
insert into t_test(num,p_num) values(3,2);
insert into t_test(num,p_num) values(4,3);
with RECURSIVE tb_a(num,p_num) as
(
select num,p_num from t_test where p_num ='0'
union all
select b.num,b.p_num from t_test b,tb_a a where a.num =b.p_num
)
select num from tb_a;

递归的相关用法

oracle中的伪列 level

--pg库中level如何实现
with RECURSIVE tb_a(num,p_num) as
(
select num,p_num,1 as lv from t_test where p_num ='0'
union all
select b.num,b.p_num,a.lv+1 as lv from t_test b,tb_a a where a.num =b.p_num
)
select num,lv from tb_a;

connect_by_isleaf 判断是否为叶子节点

--pg库中connect_by_isleaf 如何实现
with RECURSIVE tb_a(num,p_num) as
(
select num,p_num from t_test where p_num ='0'
union all
select b.num,b.p_num from t_test b,tb_a a where a.num =b.p_num
)
select a.num,a.p_num, 
case when b.num is null then '1' else '0' end is_leaf 
from tb_a a left join tb_a b on a.num =b.p_num;

10. dual

oracle 中有dual表,但是在pg库中没有

--oracle
select sysdate from dual;
--pg 
select now();

11. instr() 模糊查询

oracle instr() -> pg STRPOS()

括号里的用法一致,不需要变换

12. 日期相减或者相加

oracle 中的日期可以直接相加或者相减,但是pg库中是不可以的

pg库中两个日期字段相减或者两个日期相减可以用 EXTRACT(EPOCH FROM ...)把每个值都转换成秒数,然后执行减法, 这样会得到两个值之间的***秒***数。

SELECT EXTRACT(EPOCH FROM timestamptz '2013-07-01 12:00:00') -
       EXTRACT(EPOCH FROM timestamptz '2013-03-01 12:00:00');
Result: 10537200
    
--拓展 EXTRACT
--获取日期当中(月份)里的日域(1-31);对于interval值,是日数
SELECT EXTRACT(DAY FROM TIMESTAMP '2001-02-16 20:38:40');
结果:16
SELECT EXTRACT(DAY FROM INTERVAL '40 days 1 minute');
结果:40    
--一年中第几天
SELECT EXTRACT(DOY FROM TIMESTAMP '2001-02-16 20:38:40');
结果:47
--一周中的日,从周日(0)到周六(6)
SELECT EXTRACT(DOW FROM TIMESTAMP '2001-02-16 20:38:40');
结果:5
--oracle 可以直接相加减 默认 1 是 1天
select sysdate +1 from dual;
--pg
select now()::TIMESTAMP(0) + INTERVAL '1 day';
--常用的还有 month,year,hour,minute等
select now()::TIMESTAMP(0) + INTERVAL '1 minute';

13.正则表达式

13.1 拆分提取
--oracle regexp_substr() 拆分一般与 regexp_count() 搭配,具体使用就不介绍了
select regexp_substr('test,test1','[^,]+',1,level)  from dual connect by level <= regexp_count('test,test1','[^,]+');
结果: 
test
test1
--pg 相比较oracle而言简单一点,实现效果一样
select regexp_split_to_table('test,test1',',');
13.2 替换

oracle 和pg 都是 regexp_replace(),但是用法不一样,这个网上可以查到。

14.listagg() 拼接函数 与group by 搭配

pg库用string_agg()

create table t_test 
(
    num numeric,
    name varchar(255)
);
insert into t_test(num,name) values(1,'你');
insert into t_test(num,name) values(1,'好');
insert into t_test(num,name) values(1,'啊');
select num,string_agg(name,',') from t_test group by num;
结果:
1 你,好,啊
--注意:其中,name字段必须是varchar类型,数字类型是不能拼接的。

更多推荐