之前记了《业务系统从Oracle迁移到openGauss数据库的简单记录》:)
但事儿还没完……
没完没了啊……
PostgreSQL -> 华为openGauss
MySQL -> 中兴GoldenDB
……
官网
成熟稳定,商用领先的金融级分布式数据库。
产品坚如磐石,市场商用领先,引领行业标准制定,共建产业新生态
从中兴给的资料看出,开发上是完全兼容MySQL的,连JDBC包和驱动都是MySQL。
而且貌似不开源,也不是免费软件,所以只能当它是MySQL得了。
凡是PostgreSQL的东西openGauss都兼容。
而openGauss扩展了部分语法类似Oracle的,反过来PostgreSQL无法用。
所以为了统一和简化,都使用PostgreSQL的标准。
为了代码统一谁严谨就照着谁的做。
差异挺多的,也不知道怎么列出来更合适。
CharField1 = NumField2
(似乎openGauss也是),而PostgreSQL/MySQL需数据类型一致。CONSTRAINT
这个词,哪儿都有其它数据库不认……主要差异是数据类型,比如varchar有没有2,number,numberic,decimal……
这部分比较简单,修改一下语句就可以了,或者用Navicat
直接Data Transfer
。
PS:发现Navicat
跨数据库同步表结构和数据很方便啊(但不想改原来文章),可以先工具互导表结构,然后再从对应的库中导出DDL语句,避免了自己一个个改,yeah!
VARCHAR2
,NUMBER
,DATE
,……varchar
,numeric
,timestamp
,……varchar
,numeric
,datetime
,……写法不同,但差异很小:
Create Table TName (Field1,Field2,...)
,再COMMENT ON Table TName IS '注释'
Create Table TName (Field1,Field2,...)
,再COMMENT ON Table TName IS '注释'
,同上Create Table TName (Field1,Field2,...)
,再ALTER Table TName COMMENT = '注释'
字段注释就不一样了,涉及到部分代码逻辑:
Create Table TName (Field1,Field2,...)
COMMENT ON COLUMN TName.Field1 IS '注释'
Create Table TName (Field1,Field2,...)
COMMENT ON COLUMN TName.Field1 IS '注释'
,同上Create Table TName (Field1 COMMENT '注释1‘,Field2 COMMENT '注释2‘,...)
Alter Table
语句,而且稍微复杂(啥都要写全),所以代码里面一次注释完较为简单。正常情况下,需要CASCADE删除表关联的其它对象(索引,约束)。
对于Oracle来说我们的数据表太大了且无需闪回,所以加PURGE。
而MySQL的drop … if exists虽然很有意思,但尽量统一还是不用了。
DROP TABLE TName CASCADE CONSTRAINTS PURGE'
DROP TABLE TName CASCADE
DROP TABLE TName CASCADE
不建议通过其它方式让MySQL实现类似序列功能,因为目标数据库可能存在权限问题。
由于序列是先取出值再使用,而自增字段是Insert后再取得,所以涉及到部分代码逻辑不同。
CREATE SEQUENCE SEQXXX START WITH 1000 MAXVALUE 99999999 MINVALUE 1000
CREATE SEQUENCE SEQXXX START WITH 1000 MAXVALUE 99999999 MINVALUE 1000
,基本同上Create Table TName (Field1 int NOT NULL AUTO_INCREMENT ,Field2,...)
,Select SEQXXX.nextval from dual
select nextval('SEQXXX')
Insert into TName
记录,自增字段值赋0或Null,再select last_insert_id()
选出自增后的值。由于数据库差异,这里的表述不太准确,按实际情况改吧。
到底是选 (User/Owner)用户的表,还是 (Schema)方案的表?
select TABLE_NAME from user_tables where TABLE_NAME like ?
select tablename from pg_tables where schemaname = ? and upper(tablename) like ?
select TABLE_NAME from information_schema.tables where TABLE_SCHEMA=? and upper(TABLE_NAME) like ?
除了insert以外,大量数据导入数据库都有自己的方法。
我这里这个地方openGauss表现得很奇怪,也太慢了吧。
sqlldr...
命令,需要客户端下有这个命令文件和相关的信息文件等,这里略过。COPY ... FROM STDIN...
,其它语言没来得及研究。LOAD DATA LOCAL INFILE ... INTO TABLE ...
,需要客户端和服务端都允许这种Load文件的方式(具体安全风险自行了解)。Loading local data is disabled; this must be enabled on both the client and server sides
my.ini
文件[mysqld]
下加入local-infile=1
//客户端设置:
Property.setProperty("allowLoadLocalInfile","true");
Connection conn = DriverManager.getConnection(jdbcUrl, Property);
......
To_Char(DATE,'YYYY-MM-DD')
To_Char(DATE,'YYYY-MM-DD')
,同上date_format(DATE,'%Y-%m-%d')
不建议通过其它方式让MySQL实现类似To_Char功能,因为目标数据库可能存在权限问题。
附:不建议的MySQL自定义函数:
CREATE FUNCTION to_char(d datetime, format varchar(40)) RETURNS varchar(40)
DETERMINISTIC
begin
declare str varchar(40) DEFAULT '';
set str = replace(format, 'YYYY', '%Y');
set str = replace(str, 'yyyy', '%Y');
set str = replace(str, 'MM', '%m');
set str = replace(str, 'mm', '%m');
set str = replace(str, 'DD', '%d');
set str = replace(str, 'dd', '%d');
set str = replace(str, 'HH24', '%H');
set str = replace(str, 'hh24', '%H');
set str = replace(str, 'HH', '%h');
set str = replace(str, 'hh', '%h');
set str = replace(str, 'MI', '%i');
set str = replace(str, 'mi', '%i');
set str = replace(str, 'SS', '%s');
set str = replace(str, 'ss', '%s');
return date_format(d, str);
end
注意date和timestamp在Oracle中的区别。
select to_date('2022-06-01 23:45:59','yyyy-mm-dd hh24:mi:ss') from dual
select to_timestamp('2022-06-01 23:45:59','yyyy-mm-dd hh24:mi:ss')
select str_to_date('2022-06-01 23:45:59','%Y-%m-%d %T')
Field1 || '_' || Field2 || '_' ||...
Field1 || '_' || Field2 || '_' ||...
,同上CONCAT(Field1,'_',Field2,'_',...)
❗️❗️❗️ ⚠️ 大坑 ❗️❗️❗️
大家都支持substr,问题是substr是从1开始算Index,但Oracle从0从1都一样。
所以如果原本写了类似 substr(field1,0,x) 这种语句……
那么Oracle下没事,换其它数据库则取不到对应的结果(错得还各不相同)。
substr(name,0,2)
= substr(name,1,2)
:取得2个字符。substr(name,0,2)
= substr(name,1,1)
:取得1个字符。substr(name,0,2)
:取得0个字符(取不到)。同样不建议自定义函数实现nvl名称(宁愿在程序的SQL中加变量)。
nvl(field,-1)
coalesce(field,-1)
ifnull(field,-1)
好在【增删改】是一样的,毕竟都是SQL,集合操作嘛:
首先union(过滤重复), union all(不过滤重复) 在不同数据库中也是一样的意思,但是……
select * from T1 MINUS select * from T2
select * from T1 EXCEPT select * from T2
MINUS
或EXCEPT
,用其它SQL代替(什么是其它?呃:join, not in)。用了Oracle的(+)方式的都需要改成left join,哎……
如果一开始就不要用(+)的Oracle语法就省事儿了。
至于inner join和 where的区别,自行了解吧。结果是一样的,中间临时集大小不同而已。
select x from T1,T2 where T1.a=T2.a(+)
等价 select X from T1 left join T2 on T1.a=T2.a
select X from T1 left join T2 on T1.a=T2.a
select X from T1 left join T2 on T1.a=T2.a