香港高速VIP云机房火爆上线啦!无需备案,开通即用!配套《巅云自助建站系统3.0》将带给您飞一般的可视化拖拽建站体验,欢迎免费体验。

MySQL建表语句转PostgreSQL建表语句全纪录

一佰互联网站制作(www.yinxi.net) 发布日期 2019-03-29 10:49:32 浏览数: 69

简介:个人习惯用MySQL workbench EER数据建模,然后生成SQL语句到数据库中执行,这样表之间的关系比较直观。像下面这样:画图正向工程,生成DDL语句:忽略生成外键,以及外键索引啥的:生成的DDL语句:到数据库执行。踩坑 ...

个人习惯用MySQL workbench EER数据建模,然后生成SQL语句到数据库中执行,这样表之间的关系比较直观。

像下面这样:
  • 画图


MySQL建表语句转PostgreSQL建表语句全纪录


  • 正向工程,生成DDL语句:


MySQL建表语句转PostgreSQL建表语句全纪录


  • 忽略生成外键,以及外键索引啥的:


MySQL建表语句转PostgreSQL建表语句全纪录


  • 生成的DDL语句:


MySQL建表语句转PostgreSQL建表语句全纪录


  • 到数据库执行。

踩坑了

最近团队微调,我被调整到另一个小团队。前两天接了个新需求,于是我依然使用MySQL workbench EER建模,结果好不容易建模完成了,却被告知这个项目用的数据库是PostgreSQL!

于是就面临如下几种选择:
  • 重新找个支持导出PostgreSQL DDL语句的建模软件,再弄一遍。据我所知,macOS平台里没啥好的数据建模软件…
  • PowerDesigner用不了(除非装虚拟机,或者Wine);
  • Navicat太难用了(居然有人说Navicat是最好的数据库客户端,我只能给一个大写的服,在我看来,这货连IDEA自带数据库管理都比不上……这观点可能有点偏激,但现状是我做个查询,Navicat把查询按钮藏得很深);
  • IDEA宣布会开发类似功能,但一直没有动静;
  • 开源的PDMan,体验挺不错,但也得连个数据库控制版本。
  • 依然用MySQL workbench导出DDL,然后自己将MySQL DDL转换成PostgreSQL DDL。

我选择了自己转换SQL语句。

开源的DDL转换工具

既然要转换SQL语句,我心想,业界肯定有相关的工具啊。于是上万能的GayHub搜了下,还真有,列出来:
  • mysql-to-postgres:https://github.com/maxlapshin/mysql2postgres
  • mysql-postgresql-converter:https://github.com/lanyrd/mysql-postgresql-converter
  • 多款工具配合使用:https://yq.aliyun.com/articles/241 (不得不佩服这兄弟真有耐心啊!)

然而试用后,内心是崩溃的……生成出来的DDL要么有误,要么没有注释。

自己开发工具

考虑到我的诉求其实非常简单,只是个DDL语句转换而已,自己开发一个也不难。而且之前研读Mybatis通用Mapper源码时,知道Java世界里有个jsqlparser 的工具。

花了10分钟简单了解了下jsqlparser 后,就开撸开发工具了……花了20分钟,初版写完了,然后和该项目的同事又花了20分钟验证了下,最终确定了如下的版本。代码贴出来:

加依赖:
 <dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>1.2</version></dependency>

写代码:
public class MysqlDdl2PgDdlUtil { public static void main(String[] args) throws IOException, JSQLParserException { // 你的MySQL DDL路径 String mysqlDDLPath = "/Users/reno/Downloads/mysql.sql"; String dDLs = FileUtils.readFileToString(new File(mysqlDDLPath)); System.out.println(dDLs); System.out.println("++++++++++开始转换SQL语句+++++++++++++"); Statements statements = CCJSqlParserUtil.parseStatements(dDLs); statements.getStatements() .stream() .map(statement -> (CreateTable) statement).forEach(ct -> { Table table = ct.getTable(); List<ColumnDefinition> columnDefinitions = ct.getColumnDefinitions(); List<String> comments = new ArrayList<>(); List<ColumnDefinition> collect = columnDefinitions.stream() .peek(columnDefinition -> { List<String> columnSpecStrings = columnDefinition.getColumnSpecStrings(); int commentIndex = getCommentIndex(columnSpecStrings); if (commentIndex != -1) { int commentStringIndex = commentIndex + 1; String commentString = columnSpecStrings.get(commentStringIndex); String commentSql = genCommentSql(table.toString(), columnDefinition.getColumnName(), commentString); comments.add(commentSql); columnSpecStrings.remove(commentStringIndex); columnSpecStrings.remove(commentIndex); } columnDefinition.setColumnSpecStrings(columnSpecStrings); }).collect(Collectors.toList()); ct.setColumnDefinitions(collect); String createSQL = ct.toString() .replaceAll("`", """) .replaceAll("BIGINT UNIQUE NOT NULL AUTO_INCREMENT", "BIGSERIAL PRIMARY KEY") .replaceAll("BIGINT NULL AUTO_INCREMENT", "BIGSERIAL PRIMARY KEY") .replaceAll("BIGINT NOT NULL AUTO_INCREMENT", "BIGSERIAL PRIMARY KEY") .replaceAll("INT NOT NULL AUTO_INCREMENT", "BIGSERIAL PRIMARY KEY") .replaceAll("INT NULL AUTO_INCREMENT", "BIGSERIAL PRIMARY KEY") .replaceAll("IF NOT EXISTS", "") .replaceAll("TINYINT", "SMALLINT") .replaceAll("DATETIME", "TIMESTAMP") .replaceAll(", PRIMARY KEY \("id"\)", ""); // 如果存在表注释 if (createSQL.contains("COMMENT")) { createSQL = createSQL.substring(0, createSQL.indexOf("COMMENT")); } System.out.println(createSQL + ";"); comments.forEach(t -> System.out.println(t.replaceAll("`", """) + ";")); }); } /** * 获得注释的下标 * * @param columnSpecStrings columnSpecStrings * @return 下标 */ private static int getCommentIndex(List<String> columnSpecStrings) { for (int i = 0; i < columnSpecStrings.size(); i++) { if ("COMMENT".equalsIgnoreCase(columnSpecStrings.get(i))) { return i; } } return -1; } /** * 生成COMMENT语句 * * @param table 表名 * @param column 字段名 * @param commentValue 描述文字 * @return COMMENT语句 */ private static String genCommentSql(String table, String column, String commentValue) { return String.format("COMMENT ON COLUMN %s.%s IS %s", table, column, commentValue); }}

如代码所示,目前是借助jsqlparser 的SQL解析能力配合字符串替换的方式生成PostgreSQL的。

效果演示

转换前的DDL:
-- ------------------------------------------------------- Table `user`-- -----------------------------------------------------CREATE TABLE IF NOT EXISTS `user` ( `id` INT NOT NULL AUTO_INCREMENT COMMENT "id", `username` VARCHAR(16) NOT NULL COMMENT "用户名", `email` VARCHAR(255) NULL COMMENT "邮件", `password` VARCHAR(32) NOT NULL COMMENT "密码", `create_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT "创建时间", PRIMARY KEY (`id`));-- ------------------------------------------------------- Table `movie`-- -----------------------------------------------------CREATE TABLE IF NOT EXISTS `movie` ( `id` INT NOT NULL AUTO_INCREMENT COMMENT "Id", `name` VARCHAR(255) NOT NULL COMMENT "名称", `user_id` INT NOT NULL COMMENT "user.id", PRIMARY KEY (`id`))COMMENT = "电影表";

转换后的DDL:
CREATE TABLE "user"( "id" BIGSERIAL PRIMARY KEY, "username" VARCHAR(16) NOT NULL, "email" VARCHAR(255) NULL, "password" VARCHAR(32) NOT NULL, "create_time" TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP);COMMENT ON COLUMN "user"."id" IS "id";COMMENT ON COLUMN "user"."username" IS "用户名";COMMENT ON COLUMN "user"."email" IS "邮件";COMMENT ON COLUMN "user"."password" IS "密码";COMMENT ON COLUMN "user"."create_time" IS "创建时间";CREATE TABLE "movie"( "id" BIGSERIAL PRIMARY KEY, "name" VARCHAR(255) NOT NULL, "user_id" INT NOT NULL);COMMENT ON COLUMN "movie"."id" IS "Id";COMMENT ON COLUMN "movie"."name" IS "名称";COMMENT ON COLUMN "movie"."user_id" IS "user.id";

效果还是不错的,基本达到了我的要求。

不足

目前工具代码比较屎,如果想要改进,应该是要让工具理解MySQL DDL的词法,然后构建成例如Table、Column、Comment、Constraint、Index等对象例如:
class Table { private String name; private Column column;}class Column { private String name; private String type; // 约束,例如非空等 private Set<Constraint> constraints; // 索引 private Index index;}class Index { private String name; private String type;}enum Constraint { NOT_NULL,...;}

然后抽象一个方言枚举,并为不同的方言制作一个DDL Generator Handler,然后根据不同的方言生成不同数据库平台的DDL语句。

为什么不改进?因为没有时间,工具是为工作服务的,目前能达到我的目的,就没动力修改了,未来有需求再改进吧。

作者:周立_ITMuch

原文:https://my.oschina.net/eacdy/blog/2995462

本文仅代表作者个人观点,不代表巅云官方发声,对观点有疑义请先联系作者本人进行修改,若内容非法请联系平台管理员,邮箱2522407257@qq.com。更多相关资讯,请到巅云www.yinxi.net学习互联网营销技术请到巅云建站www.yx10011.com。
一佰互联是全国知名建站品牌服务商,我们有九年网站建设、网站制作、网页设计、php开发和域名注册及虚拟主机服务经验,提供的自助建站服务更是全国有名。近年来还整合团队优势自主开发了可视化多用户”巅云建站系统“3.0平台版,拖拽排版网站制作设计,轻松实现pc站、手机微网站、小程序、APP一体化全网营销网站建设 ,已成功的为全国上百家网络公司提供自助建站平台搭建服务。

相关新闻more

06
12月
免费企业建站,企业免费建站

免费企业建站企业免费建站企业建站背景:中国古代在历史上的经验教训,闭关只会落后,全方位的展现企业产品及品牌信息才是明智方向。网站作为信息及网... >>详情

19
04月
新手选购虚拟主机N个注意事项

现在大环境这么糟,而IDC市场竞争又异常激烈、混乱,我们在选购这些产品时,更应当加倍小心,谨防上当。 先谈禁忌吧!选购虚拟主机是有很多禁忌的... >>详情

03
05月
网站外链(反向链接)SEO优化的3个准则

一、简介网站的链接按照不同的划分标准可划分为不同的类型。通常来讲,我们将网站的链接基本分为内部链接和外部链接两种类型。按照指向不同又可划分为... >>详情

11
05月
专业网站设计公司和专业网站建设公司为我带来无

对于我这个没有文凭有没有技术的人来说,要想让自己在生活里面找到一个比较好的工作是一个非常难得事情,毕竟我是一个社会的低级人员,我能够做的一些... >>详情

营业执照. cdn加速服务 备案系统认证 网络安全协会 我们的支付方式AAA认证
上海 北京 深圳 广州 天津 杭州 南京 武汉 成都 沈阳 大连 长沙 济南 青岛 苏州 福州 无锡 哈尔滨 宁波 重庆 大庆 厦门 西安 长春 珠海 郑州 海口 昆明 太原 石家庄 温州 合肥 乌鲁木齐 南宁 南通 合肥 兰州 呼和浩特 贵阳 烟台 秦皇岛 包头 唐山 银川 汕头 连云港 威海 西宁 湛江 北海 万州 涪陵 长寿 黔江 永川 丰都 忠县 江津 南川 开县 云阳 万盛 梁平 垫江 巫山 城口 建站宝盒 免费建站 门户网站建设 微信网站 手机网站 门户网站制作

7x24小时服务电话:18581389571 传真:023-85725751 免费建站交流群:236412099 139947842(自助建站交流) E-Mail:post@yinxi.net 网站投诉:
重庆楚捷科技有限公司 一佰互联©版权所有 自助建站(www.yinxi.net,Inc.) 2001-2020 All Rights Reserved 本站程序受法律保护,网站法律顾问:ITLAW-庄毅雄律师
中华人民共和国信息产业部网站备案号:渝ICP备12000592号