【Oracle】去IOE(IBM服务器,Oracle,EMC存储),Oracle迁移postgreSQL部分问题解决方案

Oracle迁移postgreSQL部分问题解决方案

    “去IOE化"理念最早是由阿里巴巴提出。具体就是要把公司里IBM服务器、Oracle数据库、EMC存储都替换掉,    
更换为开源或国产化的选项,postgreSQL 对Oracle兼容性比较好。

1.当前时间 oracle的sysdate

处理方法:未开启事务时用now()替换,一般项目也是没有事务的。在事务中用到sysdate时,建议用clock_timestamp()替换。

例子

select sysdate from dual   等价于  select now()

2.序列 oracle的SEQNAME.NEXTVAL

处理方法:pg的NEXTVAL('SEQNAME')等效于SEQNAME.NEXTVAL
pg还提供了其他几种处理序列的方法
    currval('SEQNAME')  输出sequence的当前值 
    setval('SEQNAME')   设置sequence将要输出的下一个值

例子

select SEQNAME.NEXTVAL from dual 等价于 NEXTVAL('SEQNAME')

3.虚表 oracle的from dual

处理方法:直接去掉

4.空值处理函数 Oracle的nvl

处理方法: NVL可以用COALESCE函数替换

例子

select nvl(null,0) from dual 等价于 select COALESCE(null,0)

5.空值处理函数 Oracle的nvl2

处理方法:select nvl2(列名,1,0) from dual 等价于 select case when 列名 is null then 0 else 1   
  ------用case when 解决

例子

select nvl2(null,1,0) from dual 等价于 select case when null is null then 0 else 1 end

6.自动类型转换

pg不支持强自动类型转换 解决方法 使用 
方法1:cast(列名 as 类型)或者 
方法2:列名::类型    来转换
类型问题多集中在字符和数字之间 
pg支持弱自动转换 比如  numeric和integer,smallint,bigint之间是可以自动转换的。
					text和character之间的转换

例子 字符和数字之间的转换解决方案

select * from  tb_hello where '1'=1  
等价于 
select * from  tb_hello where cast('1' as integer)=1
select * from  tb_hello where '1' :: integer=1

7.INSTR函数 字符查找函数

Oracle的instr()有两种表达格式
格式一:instr( string1, string2 )    // instr(源字符串, 目标字符串)

格式二:instr( string1, string2 [, start_position [, nth_appearance ] ] )   // instr(源字符串, 目标字符串, 起始位置, 匹配序号)

对于格式1 
处理方法  直接用strpos替换

对于格式2
处理方法  重写一个函数instr来处理(百度搜一下)

例子

select instr('hello','l') from dual 等价于
select strpos('hello','l')

8.substr() 截取字符函数

oracle的substr()有两种格式
格式1: substr(string string, int a, int b);
			##从字符串的第a位开始截取b个字符形成新字符串
格式2:substr(string string, int a) ;

对于格式1:
如果a>0 那么可以直接替换为substring()
如果a=0 那么替换为1
如果小于0  处理就比较麻烦 下面会给出具体处理办法。

对于格式2:
直接替换为substring()

例子

格式1(a>0)和a=0的情况   --格式2情况就不讲解了
select substr('hello',0,2) from dual   ##截取字符第一位开始2位 返回截取的字符
select substr('hello',1,2) from dual   ##截取字符第一位开始2位 返回截取的字符  两者结果一致
等价于
select substring('hello',1,2)
select substr('hello',1,2)

对于a<0的情况  
select substr('hello',-a,2) from dual ##oracle从字符串倒数定位字符,所以意思就是从str倒数第一位开始截取2位组成字符串
解决方法:
select substring('hello',CHAR_LENGTH('hello')-a+2,2) ##具体意思自己理解

9.连接

oracle的连接可以简写为(+)
解决办法:替换为join   口诀:那个表的字段后(+) 那么就left join 那个表。

例子

select a.id,b.name
	from tb_hello a,tb_hi b
	where a.id=b.id(+)
等价于
select a.id,b.name
	from tb_hello a
	left join tb_hi b on a.id=b.id

10,层次查询(递归)

oracle的start with connect by 函数实现层次查询  
	对于下表sr_menu给出递归查询在oracle和pg的实现
id | parent |  title  | recursion_level
----+--------+---------+-----------------
  1 |        | level 0 |               1
  2 |      1 | level 1 |               2
  3 |      1 | level 1 |               2
  4 |      1 | level 1 |               2
  5 |      3 | level 2 |               3
  
解决:pg中使用WITH RECURSIVE语句实现递归

例子(对于上面的sr_menu表给的例子)

oracle 写法:
	select * from sr_menu          ##需要查询的列。
		start with id = 1 			##查询初始条件
	connect by prior id = parent;  	##递归条件
	
pgsql 写法:
	WITH RECURSIVE a AS (
		SELECT id, parent, title
  		FROM sr_menu
  		WHERE id = 1               ##查询初始条件
	UNION ALL
  		SELECT d.id, d.parent, d.title
  		FROM sr_menu d
  		JOIN a ON a.id = d.parent )   ##递归条件
	SELECT * FROM a; 				  ##需要查询的列。

11.数据库对象大小写

oracel  不区分大小写
pgsql   大小写区分 创建数据库对象时要小写,这样才不区分SQL的大小写

12.ROWNUM虚列

oracle会为每个表默认生成一个虚列ROWNUM,pg不会。
在我们使用ROWNUM一般分2种情况
1.限制结果集数量,用于翻页等    处理方法为 limit关键字
2.生成行号                   处理方法为 用ROW_NUMBER() OVER()来生成行号

例子

对于第一种情况

select *  from  tb_hello  where rownum <=10  
替换为
select *  from  tb_hello  where 1=1 limit 10    ##注意limit只能用在where条件结束之后


第二种情况
select *,rownum from tb_hello 
替换为
select *,ROW_NUMBER() OVER() as rownum from tb_hello

13.DECODE等判断函数

语法:decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) ##当条件的值为值1时,返回返回值1,为值2时 返回返回值2......
oracle的decode类似java的case语句   
所以在pg中也是用case when语句来实现替换

例子

select decode(X,A,B,C,D,E)from dual
等价于
select case X when A then B when C then D else E end 

14.to_char()

to_char()在oracle中几乎可以满足任何入参转换
在pg中却不同,举例说明

例子

select to_char('hello') oracle可行,pg报错  ##pg不能转换字符类型
解决: 1,重写to_char()函数 支持入参为字符串   2.使用cast()替换to_char()

select to_char(1111)   oracle可行 ,pg报错  ##pg转换数值型时必须接上精度
解决 
select to_char(1111,'fm99999')

15.to_date()

to_date()函数
oracle:
	to_date('','YYYYMMDD')只能匹配'20200102'     
'yyyy/MM/dd'和'yyyy-MM-dd'匹配所有三种时间格式字符串('20200304','2020-03-04',2020/03/04')
pg:
	pgsql的to_date()函数格式要求严格一些,‘yyyyMMdd’匹配‘2020-01-03’和‘20200103’ 。 ‘yyyy/MM/dd’匹配‘2020-01-03’和 ‘2020/01/03’  。 ‘yyyy-MM-dd' 匹配  ‘2020-01-03’和 ‘2020/01/03’  。   

16.NULL和''

ORACLE认为''等同于NULL
pg认为NULL和''不同
关于null和''解决可以用case when或者COALESCE来处理

oracle的 LENGTH('')为NULL
pg的LENGTH('')为0

oracle的TO_DATE('','YYYYMMDD')为空
pg的TO_DATE('','YYYYMMDD')为0001-01-01 BC

oracle的TO_NUMBER('',1)为NULL
pg的TO_NUMBER('',1),报错

18.ADD_MONTHS(DATE,INT)

oracle的ADD_MONTHS(DATE,INT) 指在给定的时间戳上增加或减少固定个月份
解决方法 1.创建add_month(date,int)函数  2.用- interval关键字解决

例子

select add_months(sysdate,1) from dual
等价于
select now() -interval '1 month'

19.子查询别名

oracle 子查询可以没有别名
select * from (
select * from tb_b_dim_latn_all);
或者
select * from (
select * from tb_b_dim_latn_all);
pg 必须写别名
select * from (
select * from tb_b_dim_latn_all) t;

20.查询当前登陆用户

SELECT USER FROM DUAL  ##oracle
select current_user    ##pg

21.MINUS 取差集

##orace
MINUS语句:返回两个结果集的差(即从左查询中返回右查询没有找到的所有非重复值)。

##pg
EXCEPT 返回两个结果集的差(即从左查询中返回右查询没有找到的所有非重复值)

例子

select 1,2,3 from dual
MINUS
select 1,2,3 from dual
等价于
select 1,2,3 
EXCEPT
select 1,2,3 

扩展

pg中
	INTERSECT 返回 两个结果集的交集(即两个查询都返回的所有非重复值)。
	union返回两个结果集的并集。

22.update语句

uodate 语句 在pg中尽量不要别名,oracle可以使用别名。在pg使用别名会报错

例子

update tb_hello t 
set t.hello_id=1  			##在oracle可以,在pg会报错。

23.分组连接函数和group by连用(列转行)

oracle中
	wmsys.wm_concat(列)默认拼接逗号
	LISTAGG()和wmsys.wm_concat(列)类似
解决办法
pg中提供三个函数解决
	string_agg(列,‘,’  order by 列)来替换wmsys.wm_concat()函数
	array_agg()来替换LISTAGG()函数。

同时pg还提供了xml_agg()函数。

例子

select id,wmsys.wm_concat(name)
	from tb_hello 
	group by id
	
等价于
select id,string_agg(name,',' order by name)
	from tb_hello
	group by id
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mateo-520

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值