暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle迁移postgreSQL小记(结构对象部分)

最帅dba工作笔记 2018-11-13
2741

Oracle迁移postgreSQL小记

hey!EveryBody,好久不见,小崔最近接到了一些Oracle迁移到PostgreSQL的一些问题,总结一下,希望能够帮到大家!!!!

首先我们要先确认的是,ORACLE--->PostgreSQL的差异不在数据,而是在结构,结构包括表结构,数据类型,存储过程,视图,触发器,包等结构化对象上的差距。而在ORACLE当中,这些对象都分明的十分明确,每个对象都有自己的创建方法。但是PostgreSQL里面有些对象划分的不是很明确,所以需要使用其他的去替代,我们后面细说一下。

1.数据类型。

ORACLE和PostgreSQL的数据类型有这很大的差别,在迁移数据的时候,一定要保证PostgreSQL的字段的数据类型是和ORACLE的数据类型是可以兼容的,下面我就举例一些数据类型的替换。

ORACLE

POSTGRESQL

number(10,1)

numeric(10,1)

varchar2(10)

varchar(10)

clob

text

blob

bytea

date

timestamp

2.uuid

ORACLE里面有sys_guid()函数生成uuid,但是在pg当中没有这个选项。需要用到一个contrib模块,生成一个uuid-ossp,这个可以default一个值出来做uuid。

语法为:

md5(random()::text || clock_timestamp()::text)::uuid


3.分区表

分区表在ORACLE当中是一个十分重要的功能,其可以提高数据库的搜索性能等。PostgreSQL也有这个功能,但是这个功能的语法和ORACLE的不太一样


ORACLE:

create table TEST.PARTITION

(

  nvfid    VARCHAR2(36) default sys_guid(),

  tagid    VARCHAR2(50) not null,

  deviceid VARCHAR2(20) not null,

  tagvalue VARCHAR2(20),

  tagunit  NVARCHAR2(10),

  adddate  DATE

)

partition by range (ADDDATE)

(

  partition P0 values less than (TO_DATE(' 2017-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))

    tablespace TEST

    pctfree 10

    initrans 1

    maxtrans 255

    storage

    (

      initial 64K

      next 1M

      minextents 1

      maxextents unlimited

    ),

  partition SYS_P121 values less than (TO_DATE(' 2017-07-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))

    tablespace TEST

    pctfree 10

    initrans 1

    maxtrans 255

    storage

    (

      initial 64K

      next 1M

      minextents 1

      maxextents unlimited

    ),

  partition SYS_P101 values less than (TO_DATE(' 2017-09-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))

    tablespace TEST

    pctfree 10

    initrans 1

    maxtrans 255

    storage

    (

      initial 64K

      next 1M

      minextents 1

      maxextents unlimited

    )

);

POSTGRESQL:

postgresql要想实现分区表的话目前来说还是稍微有些麻烦,具体的步骤如下:

创建主表:

create table TEST.PARTITION 

(

  nvfid    varchar(36) default md5(random()::text || clock_timestamp()::text)::uuid ,     --这里就是替换sys_guid()函数的功能

  tagid    varchar(50) not null,

  deviceid varchar(20) not null,

  tagvalue varchar(20),

  tagunit  varchar(20),

  adddate  DATE

);

创建分区表,这里的分区表归属于主表TEST.PARTITION

create table p0() inherits(TEST.PARTITION);

create table sys_p121() inherits(TEST.PARTITON);

create table sys_p101() inherits(TEST.PARTITION);

创建分区表的约束

alter table p0 add constraint PARTITION_con  check (adddate <= date '2000-01-01 00:00:00');

alter table sys_p121 add constraint  PARTITION_con check (adddate > date '2000-01-01 00:00:00' and adddate <= date '2017-07-01 00:00:00');

alter table sys_p101 add constraint  PARTITION_con check (adddate <= date '2017-09-01 00:00:00' and adddate > date '2017-07-01 00:00:00');

创建分区索引

create index PARTITION_ind1 on p0(adddate);

create index PARTITION_ind2 on sys_p121(adddate);

create index PARTITION_ind3 on sys_p101(adddate);

这里是创建触发器函数,目的是当insert到主表的时候,能够将对应的数据触发到分区表当中,触发器函数是规定了触发规则。

create or replace function PARTITION_partition_insert()

returns trigger as

$$

begin

if (new.adddate <= date '2000-01-01 00:00:00') then

        insert into p0 values (new.*);

elseif (new.adddate > date '2000-01-01 00:00:00' and new.adddate <= '2017-07-01 00:00:00') then

    insert into sys_p121 values (new.*);

elseif (new.adddate > '2017-07-01 00:00:00' and new.adddate <= '2017-09-01 00:00:00') then

    insert into sys_p101 values (new.*);

else

    raise exception ' Date out of range!!!!!';        

end if ;

return null;

end;

$$

language pluxsql ;

创建触发器

create trigger PARTITION_partition_insert_trigger before insert on TEST.PARTITION

for each row execute procedure PARTITION_partition_insert();

4.同义词

针对同义词来说我目前接触到的是试用替换的方法,postgresql官方给出了一些创建的语法,可能会需要一些插件支持,这个我还不太清楚,欢迎大家来讨论。

所以我这里给出的几个方法。

如果是一个 表/视图/物化视图等,我们可以使用创建相同规则的不同名对象去替代,如创建一个view,让这个view和这个表相同。

create view view_name as select * from  table_name ;

这样在使用的时候我们就达到了同义词的目的。


如果是函数之类的想要创建同义词,就使用嵌套的函数进行访问

原函数:

create or replace function function_name(int) returns int as $$

。。。。。。。这里假如有各种规则。。。。。

$$ language plpgsql ;


同义词函数:

create or replace function new_function_name(int) returns int as $$

select function_name($1);

$$ language plpgsql;


这样在调用的时候使用新的函数即可。


如果专门为一些表或者方法等创建了一个schema专门存放这些同义词。那么可以整体调整search_path,从而方面之后的调用。

 

5.存储过程

针对存储过程,在pg里面可以使用function去替换。我们看个例子:

ORACLE:

CREATE OR REPLACE PROCEDURE TEST.PROCTEST AS

BEGIN

  --  天:

  --ROUND(TO_NUMBER(END_DATE - START_DATE))

  --小时:

  --ROUND(TO_NUMBER(END_DATE - START_DATE) * 24)

  --分钟:

  --ROUND(TO_NUMBER(END_DATE - START_DATE) * 24 * 60)

  --秒:

  --ROUND(TO_NUMBER(END_DATE - START_DATE) * 24 * 60 * 60)

  --毫秒:

  --ROUND(TO_NUMBER(END_DATE - START_DATE) * 24 * 60 * 60 * 1000)

  update tbdevice t

     set t.onlineremark = 0

   where ROUND(TO_NUMBER(sysdate - t.lastdate) * 24* 60) > t.judegetime*60;

  update tbdevice t

     set t.onlineremark = 1

   where ROUND(TO_NUMBER(sysdate - t.lastdate) * 24* 60) < t.judegetime* 60;

     update tbdevice t

     set t.onlineremark = 2

     where t.devicetypeid=0 or t.devicecode='0';

EXCEPTION

  WHEN OTHERS THEN

    utils.handleerror(SQLCODE, SQLERRM);

END;

/


POSTGRESQL:

    CREATE OR REPLACE function TEST.PROCTEST() returns integer as $$

    

    BEGIN

      update tbdevice t

         set t.onlineremark = 0

       where ROUND(TO_NUMBER(localtimestamp - t.lastdate) * 24* 60) > t.judegetime*60;

      update tbdevice t

         set t.onlineremark = 1

       where ROUND(TO_NUMBER(localtimestamp - t.lastdate) * 24* 60) < t.judegetime* 60;

         update tbdevice t

         set t.onlineremark = 2

         where t.devicetypeid=0 or t.devicecode='0';

    EXCEPTION

      WHEN OTHERS THEN

        raise exception '(%)(%)', SQLCODE,SQLERRM;

    

    END;

    $$ language pluxsql;

function要注意一定要有返回值,而且一定注意在异常抛出那块的格式有所变化。

并且在调用postgres的函数的时候,使用的方法为select test.proctest();


6.序列

针对序列没啥说的,语法几乎相同,但是maxvalue没有ORACLE存的多。

create sequence TEST_SEQ

minvalue 1

maxvalue 9999999999999999

start with 425

increment by 1

cache 20;

只是在使用的时候和ORACLE有所区别

select nextval(TEST_SEQ);

select currval(TEST_SEQ);

select lastval(TEST_SEQ);



7.触发器

触发器我们在上面的分区表有过一点的介绍,postgresql的触发器创建和ORACLE的有点差异,postgresql要先创建触发器函数,这个函数规定了这个触发器的触发规则,之后再创建触发器函数。我们看下:

ORACLE:

create or replace trigger ZGZY.SY_APPROVAL_ID_TRIGGER

  before insert on sy_approval  

  for each row

declare

  -- local variables here

begin

      if :new.approvalid is null then

    select SY_APPROVAL_ID_SEQ.nextval into :new.approvalid from sys.dual;

  END IF;

end SY_APPROVAL_ID_TRIGGER;

/

POSTGRES:

创建序列

create sequence SY_APPROVAL_ID_SEQ minvalue 1 maxvalue 9999999999;

创建表

create table SY_APPROVAL(id int);

创建触发器函数

create or replace function PROC_SY_APPROVAL_ID_TRIGGER()

returns trigger

as

$$

   begin

     if new.ID is null

     then

new.ID=(select nextval('SY_APPROVAL_ID_seq'));

     return new;

   else

     return new;

     end if;

   end;

$$ language pluxsql;

创建触发器

create trigger SY_APPROVAL_ID_TRIGGER before insert on SY_APPROVAL for each row  execute procedure PROC_SY_APPROVAL_ID_TRIGGER();


8.package包

postgresql没有办法创建包这种特殊的对象,但是可以使用其他的方法进行替代,比如专门创建一个schema,然后将函数(存储过程)存放到这个schema下,使用的时候就调用这个schema下的函数。

9.其他

下面我说一些零碎的点:

ORACLE当中有dual,但是postgresql没有,查询使用select 1+2 这样既可。

ORACLE有些内部函数包,如DBMS_OUTPUT,DBMS_SQL,UTIL_FILE,UTIL_MAIL,这种函数只能创建,否则能用在postgresql里。

针对当前系统时间的选取,ORACLE可以使用sysdata()函数;postgresql使用localtimestamp或者now()。

创建view的时候,ORACLE可以加force强制创建view,但是postgresql没有这个功能。必须得有基表才可以。


 上面就是ORACLE结构对象迁移到postgresql的步骤,欢迎大家私信讨论(小崔不会开文章留言啊!!!!)。


THAT'S ALL 

BY CUI PEACE!!!





本文分享自微信公众号 - 最帅dba工作笔记,如有侵权,请联系 service001@enmotech.com 删除。
最后修改时间:2019-12-18 15:26:10
文章转载自最帅dba工作笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论