写在前文:
近期由于公司业务产品发展需要,要求项目逐渐国产化:(1)项目国产操作系统部署;(2)数据库国产化;国产数据库最终选型为highgo(瀚高),该数据库基于pg开发,所以要求先将mysql适配到postgresql数据库;
一、初识postgresql
1.1 docker安装postgresql
1.1.1 镜像拉取
dockerhub官网选取自己想安装的版本(
https://hub.docker.com/_/postgres/tags
),我这里选取的是13.9版本;
拉取镜像到本地
docker pull postgres:13.9
1.1.2 执行镜像安装postgresql
docker run --name 1.postgres \
--restart=always \
-e POSTGRES_PASSWORD='jY%kng8cc&' \
-p 5432:5432 \
-v /data/postgresql:/var/lib/postgresql/data \
-d postgres:13.9
1.1.3 创建数据库,设置默认查询模式
-- 建库
CREATE DATABASE "test"
OWNER = "testuser" -- 数据库用户
-- 创建模式
CREATE SCHEMA "test" AUTHORIZATION "test";
-- 设置默认查询模式 pg连接时默认使用public这个schmel,想让项目连接时使用自己创建的模式需要修改一下默认查询模式
ALTER ROLE testuser SET search_path="test";
1.2 postgresql学习
这里放上一个学习地址,大家可以参照性学习,边使用边学习
https://www.sjkjc.com/postgresql/psql-commands/
1.3 项目中引入postgresql数据库
1.3.1 版本问题
postgresql-42.2.10(支持PostgreSQL 42)
pg驱动版本:springboot2.5.14中默认集成的是42.2.25
1.3.2 添加maven依赖
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
1.3.3 配置文件修改
# 1.postgres为容器名称,也可以直接指定ip
pring.datasource.url=jdbc:postgresql://1.postgres:5432/test?autoReconnect=true&autoReconnectForPools=true&useUnicode=true&characterEncoding=utf8&createDatabaseIfNotExist=true&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
spring.datasource.username=testuser
spring.datasource.password=test
spring.datasource.driver-class-name=org.postgresql.Driver
二、 MYSQL和PG基础语法差异汇总整理
2.1 数据结构对比
mysql
|
postgresql
|
TINYINT
|
SMALLINT
|
SMALLINT
|
SMALLINT
|
MEDIUMINT
|
INTEGER
|
BIGINT
|
BIGINT
|
FLOAT
|
REAL
|
DOUBLE
|
DOUBLE PRECISION
|
BOOLEAN
|
BOOLEAN
|
TINYTEXT
|
TEXT
|
TEXT
|
TEXT
|
MEDIUMTEXT
|
TEXT
|
LONGTEXT
|
TEXT
|
BINARY(n)
|
BYTEA
|
VARBINARY(n)
|
BYTEA
|
TINYBLOB
|
BYTEA
|
BLOB
|
BYTEA
|
MEDIUMBLOB
|
BYTEA
|
LONGBLOB
|
BYTEA
|
DATE
|
DATE
|
TIME
|
TIME [WITHOUT TIME ZONE]
|
DATETIME
|
TIMESTAMP [WITHOUT TIME ZONE]
|
TIMESTAMP
|
TIMESTAMP [WITHOUT TIME ZONE]
|
AUTO_INCREMENT
|
SERIAL , BIGSERIAL
|
column ENUM (value1, value2, […]
|
column VARCHAR(255) NOT NULL, CHECK (column IN (value1, value2, […])) pg可以自定义数据类型实现类似效果: CREATE TYPE mood AS ENUM ('sad','ok','happy'); CREATE TABLE person ( current_mood mood ... )
|
2.2 基础语法差异对比
语法差异
|
mysql
|
postgresql
|
是否相同
|
分页
|
select * from t1 limit 2,2;
|
select * from tbl limit 2 offset 2;
|
否
|
插入数据时:如果不存在则insert,存在则update
|
replace实现
|
upsert
|
否
|
大小写兼容
|
通过配置可兼容
|
表字段或表名为大写时,字段或表名必须添加双引号
|
否
|
if(), case when
|
if(), case when 条件1 then 符合值 else 不符合值 end;
|
case when 条件1 then 符合值 else 不符合值 end;
|
否
|
round(字段,小数位数)
|
round(字段,小数位数)
|
round(case(‘字段’ as numeric),小数位数)
|
否
|
null值判断
|
支持 ifnull(),NVL(),COALESCE()
|
支持COALESCE()
|
否
|
Update-单表更新
|
相同
|
相同(不可全表更新)
|
是
|
update-更新单表多个字段
|
相同
|
相同
|
是
|
update-更新并返回
|
select tem1,tem2 from update test set tem1 = '',tem2 = ''
|
UPDATE test SET tem1 = '',tem2 = '' RETURNING tem2,tem2;
|
否
|
Update表关联更新
|
相同
|
相同
|
是
|
Insert-单行插入
|
相同
|
相同
|
是
|
Insert-插入指定字段
|
相同
|
相同
|
是
|
insert-插入多行
|
相同
|
相同
|
是
|
insert-插入并返回
|
不支持
|
INSERT INTO() RETURNING did
|
否
|
Insert-插入,存在则更新
|
INSERT INTO () VALUE() ON DUPLICATE KEY UPDATE name =
EXCLUDED.name
|
INSERT INTO distributors ( did , dname ) VALUES ( 9 , ' Antwerp Design' ) ON CONFLICT (did)DO UPDATE SET name =
EXCLUDED.name
|
否
|
insert-不存在插入,存在更新
|
replace实现
|
upsert语句
|
否
|
SELECT
|
相同
|
相同
|
是
|
DELETE
|
DELETE FROM table
|
DELTE FROM table(不可全表删除)
|
是
|
DELETE
|
DELETE FROM table WHERE
|
DELETE FROM table WHERE
|
是
|
DELETE-删除并返回
|
不支持
|
DELETE FROM table WHERE RETURNING * ;
|
|
INDEX-add
|
支持alter,create创建
|
支持create
|
|
INDEX-delete
|
支持alter,drop
|
支持drop
|
|
字符串常量
|
支持单双引号
|
支持双引号
|
否
|
插入数据时自增主键
|
写法一:insert into t1(name) values(‘zhangshan’); 写法二:insert into t1(id, name) values(null, ‘zhangshan’);
|
insert into t1(name) values(‘zhangshan’);
|
否
|
库名长度
|
无强制限制
|
库名、表名限制命名长度,建议表名及字段名字符总长度小于等于63。
|
|
三、MYSQL数据结构转换PG数据结构
3.1 mysql数据结构转换PG数据结构
网上有很多转换工具,有些需要收费,这里借助一个最简单最常用的工具-navicat premium(我这里使用的是16版本)转换mysql数据结构到PG的数据结构
至此,一份pg的数据结构就保存完整了
(注意:此时转换出来的数据结构会存在一些错误,还需要额外手动处理一些问题)
3.2 MYSQL转换PG数据结构存在的问题及解决方案
3.2.1 默认值丢失问题default
(1)
时间字段的CURRENT_TIMESTAMP默认值丢失
解决方案:
-- 从mysql默认表information_schema中获取默认为CURRENT_TIMESTAMP列的信息
SELECT TABLE_NAME,column_name,column_default,extra FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND column_default = 'CURRENT_TIMESTAMP';
-- 拼接所有时间字段默认为CURRENT_TIMESTAMP的alter 语句,提取到脚本中执行
SELECT
CONCAT("ALTER TABLE \"bigdata-web\".\"",TABLE_NAME, "\" ALTER COLUMN ","\"",column_name,"\"", " SET DEFAULT ", column_default, ";")
FROM information_schema.columns
WHERE
table_schema = 'bigdata-web' and column_default is not null AND column_default = 'CURRENT_TIMESTAMP';
(2)时间字段类型的on update CURRENT_TIMESTAMP,PG中无该使用方式
解决方案:
利用触发器和pg扩展函数实现更新数据时更新时间字段值
-- 安装pg扩展函数moddatetime(使用pg的useradmin用户)
create extension moddatetime;
ALTER FUNCTION "moddatetime"() OWNER TO "test用户";
-- 触发器语句:create trigger gmt_modified_timestamp_trigger before update on test_ly for each row execute procedure moddatetime(gmt_modified);
-- 查询所有设置了on update CURRENT_TIMESTAMP的列
SELECT TABLE_NAME,COLUMN_NAME,EXTRA,DATA_TYPE FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND column_default != '' AND column_default = 'CURRENT_TIMESTAMP' AND EXTRA = 'on update CURRENT_TIMESTAMP';
-- 拼接处理默认值为on update CURRENT_TIMESTAMP字段类型的默认值,添加触发器的语句
SELECT CONCAT("create trigger ", COLUMN_NAME, "_trigger ","before update on \"", TABLE_NAME, "\" for each row execute procedure moddatetime(\"",COLUMN_NAME,"\");") FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND column_default != '' AND column_default = 'CURRENT_TIMESTAMP' AND EXTRA = 'on update CURRENT_TIMESTAMP';
(3)其他默认值可以参考上面拼接处理,如字符串,数字
-- 拼接所有默认值为字符串的alter语句
SELECT TABLE_NAME,column_name,column_default,DATA_TYPE,extra FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND column_default != 'CURRENT_TIMESTAMP' AND DATA_TYPE = 'varchar' AND column_default != '';
SELECT
CONCAT("ALTER TABLE \"bigdata-web\".\"",TABLE_NAME, "\" ALTER COLUMN ","\"",column_name,"\"", " SET DEFAULT '", column_default, "';")
FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND column_default != 'CURRENT_TIMESTAMP' AND DATA_TYPE = 'varchar' AND column_default != '';
-- 拼接默认值字段为enum的alter语句
SELECT * FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND column_default != '' AND DATA_TYPE = 'enum';
SELECT
CONCAT("ALTER TABLE \"bigdata-web\".\"",TABLE_NAME, "\" ALTER COLUMN ","\"",column_name,"\"", " SET DEFAULT '", column_default, "';")
FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND column_default != '' AND DATA_TYPE = 'enum';
-- 查询默认值为数字的列,拼接alter语句 除了tinyint(1) TABLE_NAME,column_name,column_default,DATA_TYPE,extra
SELECT * FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND column_default != 'CURRENT_TIMESTAMP' AND DATA_TYPE IN('tinyint', 'int', 'bigint') AND column_default != ''
AND COLUMN_TYPE != 'tinyint(1)' and
table_name = 't_user'
SELECT
CONCAT("ALTER TABLE \"bigdata-web\".\"",TABLE_NAME, "\" ALTER COLUMN ","\"",column_name,"\"", " SET DEFAULT ", column_default, ";")
FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND column_default != 'CURRENT_TIMESTAMP' AND DATA_TYPE IN('tinyit', 'int', 'bigint') AND column_default != ''
AND COLUMN_TYPE != 'tinyint(1)';
-- double
SELECT * FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND DATA_TYPE IN('double') AND column_default != '';
SELECT
CONCAT("ALTER TABLE \"bigdata-web\".\"",TABLE_NAME, "\" ALTER COLUMN ","\"",column_name,"\"", " SET DEFAULT ", column_default, ";")
FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND DATA_TYPE IN('double') AND column_default != '';
-- decimal
SELECT * FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND DATA_TYPE IN('decimal') AND column_default != '';
SELECT
CONCAT("ALTER TABLE \"bigdata-web\".\"",TABLE_NAME, "\" ALTER COLUMN ","\"",column_name,"\"", " SET DEFAULT ", column_default, ";")
FROM information_schema.columns
WHERE table_schema = 'bigdata-web' and column_default is not null AND DATA_TYPE IN('decimal') AND column_default != '';
(4)MYSQL的tinyint(1)(业务代码中boolean值)转换为了int2
navicat工具转换映射时将mysql的bit(1)转换为了int2,需要处理该部分字段
-- tinyint
SELECT * FROM information_schema.columns
WHERE table_schema = 'test-database' AND COLUMN_TYPE = 'tinyint(1)'
ORDER BY TABLE_NAME
-- 批量转换语句拼接
3.2.2 自增id设置丢失
navicat工具转换时将自增id设置丢失了
解决方案:
(1)修改建表语句,使用SERIAL关键字
(2)修改已经创建的表的某个字段为自增
--1、在PostgreSQL当中,我们实现ID自增首先创建一个关联序列,以下sql语句是创建一个从1开始的序列:
CREATE SEQUENCE menu_id_seq START 1;
--2、设置该字段默认值nextval('menu_id_seq'::regclass)
ALTER TABLE menu ALTER COLUMN id SET DEFAULT nextval('menu_id_seq'::regclass);
四、业务代码中的语法差异转换
4.1 常见修改场景汇总
序号 | 场景 | 示例 |
1 | mapper接口方法上使用注解编写sql语句 | @SELECT("SELECT * FROM TEST") |
2 | mapper的xml文件中的语句 | |
3 | mybatis-plus使用的实体类相关特殊列名修改 |
4.2 业务代码语法修改问题汇总
序号 | 差异关键字 | 差异描述 | mysql示例 | pg示例
| 1 | limit | limit 0,1 改成 limit 1 offset 0 | select * from t_user limit 0,1 | select * from t_user limit 1 offset 0 | 2 | 字段大小写 | 查询字段为驼峰命名,加上双引号,select \"startTime\" form ... | - | - | 3 | ifnull | 没有ifnull函数,改用COALESCE()函数, | select ifnull(avatar, 'aa'),"name" from t_user; | select COALESCE(avatar, 'aa'),"name" from t_user; | 4 | DATE_SUB() | 没有DATE_SUB()时间计算函数,改用select now() + '1 seconds' 或 select now() + '-1 seconds' | select DATE_SUB(logintime,INTERVAL 1 DAY) from t_user; | select logintime + '1 days' from t_user; | 5 | 别名大小写 | 查询字段的别名也需要用双引号包起来,select start_time as \"startTime\" from ... | - | - | 6 | 正则表达式、REGEXP | 正则表达式匹配,where taget_name ~ '^123$|asd'...,其中~为匹配正则表达式区分大小写,~*为不区分大小写,前面加叹号则为不匹配正则表达式如:!~ | select * from t_user where name REGEXP '^adm*'; | select * from t_user where name ~ '^adm*'; | 7 | binary | mysql的where判断加上binary来区分大小写,where binary id = ‘abc’,在pg中是直接区分大小写的,将binary去掉就行 | select * from t_user where binary name = 'ADMIN'; | select * from t_user where name = 'ADMIN'; | 8 | group_concat_max_len | set session group_concat_max_len=...在pg中没有,注释 | - | - | 9 | GROUP_CONCAT() | GROUP_CONCAT()函数没有,使用array_to_string(array_agg(target_name), ',') from ... 代替 | select GROUP_CONCAT(industry) from t_company group by province; | select array_to_string(array_agg(industry), ',') from t_company group by province; | 10 | ISNULL | ISNULL没有使用is null来进行判断 | select * from t_user where ISNULL(avatar); | select * from t_user where avatar is null; | 11 | &&,|| | &&和||没有这个符号,用and和or替换 | select * from t_user where ISNULL(avatar) && realname = '日志管理员'; | select * from t_user where avatar is null and realname = '日志管理员'; | 12 | date_format() | date_format()函数用不了,换成 to_char,select to_char(create_time, 'yyyy-MM-dd hh24:mi:ss') from ... | select date_format(logintime, '%Y-%m-%d') from t_user; | select to_char(logintime, 'yyyy-MM-dd') from t_user; | 13 | if() | 没有if()函数,改用 case when 条件 then 值 else 值 end | select if(name = 'admin', true, false) as isAdmin from t_user | select case when name = 'admin' then true else false end as isAdmin from t_user | 14 | FIND_IN_SET() | where FIND_IN_SET('123', user_ids) ... 使用不了,换成 where '123' = ANY(string_to_array(user_id, ',')) ... | select * from t_company where find_in_set('浙江省', address); | select * from t_company where '浙江省' = ANY(string_to_array(address, ',')); | 15 | 数字字符串比较、连表 | mysql中能直接对数字和字符串进行=相等判断,pg不行,换成,'123' = cast(123 as VARCHAR) 或者 123 = cast('123' as INTEGER);或者123 = '123'::INTEGER 例如 select * from t_model_layout_task_record as r left join t_model_layout_form as f on r.formId = f.id,其中r.formId是vachar,f.id是int,这样连表是报错的, 改成:select * from t_model_layout_task_record as r left join t_model_layout_form as f on r.formId = cast(f.id as VARCHAR) | select * from t_model_layout_task_record as r left join t_model_layout_form as f on r.formId = f.id | select * from t_model_layout_task_record as r left join t_model_layout_form as f on r.formId = cast(f.id as VARCHAR) | 16 | SYSDATE() | 没有 SYSDATE() 函数,换成 NOW() | select SYSDATE(); | select now(); | 17 | from_unixtime() | 没有from_unixtime()函数,换成to_timestamp() | select from_unixtime(1673833489);
| select to_timestamp(1673833489); | 18 | auto_increment | mysql查询information_schema.tables的auto_increment字段获取主键自增的值,而pg的information_schema.tables中不存在auto_increment。 pg通过该函数 pg_get_serial_sequence(‘库名.表名’, '自增字段名') 获取表的自增值 | - | - | 19 | unix_timestamp() | 没有unix_timestamp()函数,换成date_part('epoch', now())::integer,例如,select date_part('epoch', start_time)::integer from t_model_layout_task_record | select unix_timestamp(createtime) from t_user; | select date_part('epoch', createtime)::integer from t_user; | 20 | ON DUPLICATE KEY UPDATE | mysql的存在则更新写法,pg换成, 改成: INSERT INTO 表名(列1,列2...) VALUES ('值1', '值2', ...)ON CONFLICT(唯一或排除约束字段名) DO UPDATE SET 列1='值', 列2='值', ...; 如果是批量插入的话改成: INSERT INTO 表名(列1,列2...) VALUES ('值1', '值2', ...)ON CONFLICT(唯一或排除约束字段名) DO UPDATE SET 列1=excluded.列1, 列2=excluded.列2, ...; 需要注意的是: 唯一或排除约束字段名必须是一个唯一索引或唯一联合索引,如果填写多个唯一索引则不生效,如果要生效的话,必须把他们建立成一个唯一联合索引。 | insert into t_user(id,name,logintime,PASSWORD,createuser,updateuser) values(1,'test',now(),'test',1,1) on duplicate key update logintime = values(logintime); | insert into t_user(id,name,logintime,"PASSWORD",createuser,updateuser) values(1,'test',now(),'test',1,1) ON CONFLICT(id) DO UPDATE SET logintime=excluded.logintime; | 21 | instr() | 没有instr()函数,改成like。例: SELECT * FROM user WHERE INSTR(username,'2')>0 SELECT * FROM user WHERE username like '%2%' | select * from t_user where INSTR(name,'a')>0 | select * from t_user where name like '%a%' | 22 | ` ` | 查询的字段 ` 号换成双引号,select \"name\" from ... | select `name` from t_user; | select "name" from t_user; | 23 | 表名大小写 | 表名称中含有大写字母需要用双引号将表格名称包含起来 | select PASSWORD from t_user; | select "PASSWORD" from t_user; | 24 | 表名别名大小写 | 查询结果别名中有大写需要用双引号包含起来如果不包含起来查询结果会自动转为小写,select area_id as "areaId" from ... | - | - | 25 | GROUP BY | GROUP BY 分组查询不能查不在分组内的数据(也不能对非GROUP BY的字段进行ORDER BY排序),需要变成连表查询,链表查需要注意是否有重复数据。 例如: SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname ORDER BY wmname;(查询失败) 如果没有重复数据换成: SELECT m.cname, m.wmname, t.mx FROM ( SELECT cname, MAX(avg) AS mx FROM makerar GROUP BY cname ) t JOIN makerar m ON m.cname = t.cname AND t.mx = m.avg ORDER BY m.wmname ; 如果有重复数据需要进行去重则换成:(利用窗口函数) SELECT cname, DISTINCT ON(wmname)wmname wmname, MAX(avg) OVER (PARTITION BY wmname) AS mx FROM makerar 如果需要对不是去重的字段进行排序则在最外层加上排序: SELECT * FROM ( SELECT cname, DISTINCT ON(wmname)wmname wmname, MAX(avg) OVER (PARTITION BY wmname) AS mx FROM makerar ) bb ORDER BY m.wmname | select name,count(type) from t_company group by type order by type desc; | select aa.name, aa.count from (select distinct on(type)type "type",name,count(type) OVER (PARTITION BY type) from t_company) aa order by aa.type desc; | 26 | uuid() | uuid()函数不存在,安装扩展函数 create extension "uuid-ossp"; | select uuid(); | select uuid_generate_v4(); | 27 | 时间模糊查询 | 在进行时间模糊查询的时候需要转换一下时间,例如: SELECT * FROM xxx WHERE to_char(create_time, 'yyyy-MM-dd hh24:mi:ss') LIKE CONCAT(#{mouth},'%') | select realname,logintime from t_user where logintime like '%2023%' | select realname,logintime from t_user where to_char(logintime, 'yyyy-MM-dd hh24:mi:ss') like '%2023%' | 28 | replace into | 在业务先删除在插入。 如果可以的话可以用下面的写法,看业务需要 pg 没有这个语法, 如果根据以为能改成存在更新不存在就插入的话可以用以下写法: INSERT INTO 表名(列1,列2...) VALUES ('值1', '值2', ...)ON CONFLICT(唯一或排除约束字段名) DO UPDATE SET 列1='值', 列2='值', ...; 如果是批量插入的话改成: INSERT INTO 表名(列1,列2...) VALUES ('值1', '值2', ...)ON CONFLICT(唯一或排除约束字段名) DO UPDATE SET 列1=excluded.列1, 列2=excluded.列2, ...; 需要注意的是: 唯一或排除约束字段名必须是一个唯一索引或唯一联合索引,如果填写多个唯一索引则不生效,如果要生效的话,必须把他们建立成一个唯一联合索引。 | - | - | 29 | like | 如果对int字段进行like判断需要将字段转为VARCHAR类型,例如: where state::VARCHAR like concat('%', #{state},'%') ... | select id from t_user where id like '%2023%' | select id from t_user where id::varchar like '%2023%' | 30 | 时间/between and | 如果判断between and是时间, 情况1、数据库是timestamp,and两边是字符串格式为'yyyy-MM-dd HH:mm:ss'则 where to_char(create_time, 'yyyy-MM-dd hh24:mi:ss') between #{startTime} and #{endTime} | select * from t_user where logintime between '2023-01-01 00:00:00' and '2023-01-16 23:59:59' | select * from t_user where to_char(logintime, 'yyyy-MM-dd hh24:mi:ss') between '2023-01-01 00:00:00' and '2023-01-16 23:59:59' | 31 | 关键字 | 关键字: name、value、label、moudle 需要双引号包含起来 | - | - | 32 | 运算符号 + | mysql 返回结果可直接通过+拼接字符串, pg不支持,改成concat方法 | - | - | 33 | 实体类 | 实体类里面@TableField里写的字段有大写或者 ` 号的要改成双引号,例如 @TableField("\"order\"")、@TableField("\"createTime\"") | - | - | 34 | curdate() | 没有curdate()函数,换成,current_date。注意没有括号例如:select current_date; | select curdate(); | select current_date; | 35 | inet_aton()、inet6_aton() | 没有inet_aton()和inet6_aton()函数,使用inet()函数进行判断 | select inet_aton('1.1.1.1') | select inet('1.1.1.1') | 36 | locate() | 没有locate()函数,换成position() | select locate('b','ayyvkhlbm') | select position('b' in 'ayyvkhlbm') | 37 | ORDER BY | 按照指定字段值排序 | ORDER BY FIELD (`field`, value1, value2) | 使用CASE WHEN END替代(eg:ORDER BY CASE field WHEN value1 THEN WHEN value2 THEN 2 END) | 38 | convert() | 没有convert()函数,用convert_from()替换 | convert(vendor using gbk) | convert_from(vendor::bytea, 'gbk') | 39 | bool字段查询和插入,不可以使用0,1;修改PG数据库内置转换规则SQL语句: update pg_cast set castcontext='i' where castsource ='integer'::regtype and casttarget='boolean'::regtype;
| update pg_cast set castcontext='i' where castsource ='integer'::regtype and casttarget='boolean'::regtype;
| -- eg: type为bool类型 insert into test_ly(id, type) VALUES(2,0); select * from test_ly where type = 1; | -- eg: type为bool类型 insert into test_ly(id, type) VALUES(2,0); select * from test_ly where type = 1; | 40 | 关联字段,条件查询字段类型不一致时,产生报错问题;强制转换,如转换为字符串 ::varchar,bigint ::BIGINT | ::BIGINT | - | select u.id from t_user as u left join t_cascade_work_order w on u.id = w.author_id::BIGINT; | 41 | substring_index() | PG中无该函数,创建自定义函数,实现该功能 CREATE OR REPLACE FUNCTION substring_index(varchar, varchar, integer)
RETURNS varchar AS $$
DECLARE
tokens varchar[];
length integer ;
indexnum integer;
BEGIN
tokens := pg_catalog.string_to_array($1, $2);
length := pg_catalog.array_upper(tokens, 1);
indexnum := length - ($3 * -1) + 1;
IF $3 >= 0 THEN
RETURN pg_catalog.array_to_string(tokens[1:$3], $2);
RETURN pg_catalog.array_to_string(tokens[indexnum:length], $2);
END IF;
$$ IMMUTABLE STRICT LANGUAGE PLPGSQL;
| | |
MySQL到 PostgreSQL转换器
Lanyrd MySQL到 PostgreSQL转换脚本。 小心使用。
该脚本是为满足我们特定的 数据库和列要求而设计的-值得注意的是,由于我们遇到的unicode大小问题,该脚本使VARCHAR的长度增加了一倍,在所有外键上放置了索引,并假定您使用Django进行列输入。
首先,以 PostgreSQL兼容格式 转储 MySQL数据库
mysqldump --compatible= postgresql --default-character-set=utf8 \
-r databasename. mysql -u root databasename
然后,使用dbconverter.py脚本对其进行 转换
python db_converter.py databasename. mysql databasename.p sql
它将进度打印到终端。
这一段时间在帮客户写一个小型的CRUD项目,原项目是MySQL数据库,客户有一个要求就是必须使用PostgreSQL数据库,本来以为转换非常方便,没想到还是折腾了一下。预先提醒一下,我只完成了数据库表结构、数据的转换,其他的外键、视图没有涉及。
首先MySQL与PostgreSQL的语法还是有些差别,无法无缝转换使用。于是在网上找到了一个收费工具,MySQL to PostgreSQL,demo版本,有如下限制:
1、数据记录,不超过50条
2、不能转换外键及视图
第二条限制还好办,我使用的MySQ
MySQL和PostgreSQL是两种常用的关系型数据库管理系统(RDBMS)。它们使用的是不同的SQL语法和功能。因此,将MySQL的SQL语句转换为PostgreSQL的语法是一项常见的任务。
为了实现这种转换,可以使用一些工具和技术。以下是一些常用的工具和方法:
1. 使用在线转换工具:有一些在线工具可用于将MySQL语句转换为PostgreSQL语法。你只需将MySQL语句粘贴到工具中,然后选择将其转换为PostgreSQL语法。这些工具会自动将语句转换为相应的PostgreSQL语法。一些流行的在线转换工具包括SQLines SQL转换器和fromsqltocode工具。
2. 使用第三方软件:有一些第三方软件可用于将MySQL数据库迁移到PostgreSQL,并自动转换语句。例如,SQLMaestro的MySQL到PostgreSQL工具可以帮助你轻松将MySQL语句转换为PostgreSQL语法,并将数据库迁移到PostgreSQL。
3. 手工转换:如果对SQL语法和MySQL和PostgreSQL的功能有深入的了解,也可以手动将MySQL语句转换为PostgreSQL语法。这需要查看和理解两个数据库的语法规则,然后逐个转换每个语句。手动转换可能需要花费一些时间和精力,但对于复杂的查询可能是最灵活和可靠的方法。
转换MySQL语法为PostgreSQL语法需要注意以下几个主要差异:
- 数据类型:MySQL和PostgreSQL使用不同的数据类型,因此在转换过程中需要注意这一点,并将MySQL的数据类型转换为PostgreSQL的等效类型。
- 语法:MySQL和PostgreSQL在某些语法方面也有所不同,例如连接语法、子查询语法等。所以需要了解并适当地转换这些差异。
总之,将MySQL语法转换为PostgreSQL语法的工具和方法有很多选择。无论选择哪种方法,都需要对SQL语法和MySQL、PostgreSQL的特定功能有深入的了解。
|