我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

个人习惯用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("`", "\"") + ";"));
        });
    }

    
    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;
    }

    
    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语句。

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

原文

http://www.itmuch.com/work/mysql-ddl-2-pgsql-ddl/ ,转载请说明出处。

干货分享

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

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

MySQL如何查看建库建表语句

目录mysql查看建库建表语句MySQL建库建表语句分享建库语句建表语句总结MySQL查看建库建表语句有时候我们需要查看mysql的建表语句,以下是具体操作查看数据库创建语句SHOW CREATE DATABASEjs ZOOG;类似
2023-02-18

mysql怎么用sql语句创建表

要使用 sql 在 mysql 中创建表,可以使用 create table 语句。语法为:create table table_name (column_name data_type [not null] [default default
mysql怎么用sql语句创建表
2024-04-22

mysql在建表语句中添加索引

普通索引创建创建普通索引,即不添加 UNIQUE、FULLTEXT 等任何参数。【例】创建表名为 score 的数据表,并在该表的 id 字段上建立索引,SQL 语句如下:CREATE table score( id int(11) AUTO_INC
mysql在建表语句中添加索引
2015-11-16

mysql建表语句要在什么里面

mysql 建表语句可以在以下位置编写:mysql 控制台或命令提示符数据库管理工具应用程序或脚本MySQL 建表语句在哪里编写 MySQL 建表语句?MySQL 建表语句通常在以下位置编写:MySQL 控制台或命令提示符(CMD):使
mysql建表语句要在什么里面
2024-04-22

oracle创建表语句怎么写

oracle 数据库中创建表的语法:create table ( [not null] [primary key] [references (引用列名)] );Oracle 创建表语句如何创建表?在 Oracle 数据库中,使用
oracle创建表语句怎么写
2024-05-21

navicat如何查看建表语句

在 navicat 中查看建表语句的方法如下:选中并打开要查看建表语句的表。右键单击该表并选择“脚本”>“查看建表语句”。查看新查询选项卡中显示的建表语句。如何在 Navicat 中查看建表语句在 Navicat 中查看建表语句非常简单,
navicat如何查看建表语句
2024-04-23

sql创建表语句怎么写

sql create table 语句用于创建包含指定列名和数据类型的新表。参数包括表名、列名、数据类型、not null 约束、null 约束和约束。例如,"create table customers (customer_id int
sql创建表语句怎么写
2024-05-30

navicat怎么查询建表语句

使用 navicat 查询建表语句的方式如下:连接到数据库。选择要查询的表,右键单击并选择“脚本”>“生成创建脚本”。查看生成的脚本,其中包含创建表的语句。Navicat 查询建表语句Navicat 是一款功能强大的数据库管理工具,可以方
navicat怎么查询建表语句
2024-04-24

navicat怎么用语句创建表

在 navicat 中使用 sql 语句创建表,需要执行以下步骤:1. 连接到数据库。2. 打开 sql 编辑器。3. 编写并执行 create table 语句。4. 验证表创建是否成功。如何使用语句在 Navicat 中创建表Navi
navicat怎么用语句创建表
2024-04-23

如何实现MySQL中创建表的语句?

如何实现MySQL中创建表的语句?在MySQL数据库中,创建表是非常重要的操作之一。创建表的语句需要考虑到表的结构、字段类型、约束等各种因素,以确保数据存储的准确性和完整性。下面将详细介绍如何在MySQL中创建表的语句,包括具体的代码示例。
如何实现MySQL中创建表的语句?
2023-11-09

怎么在mysql使用sql语句创建表

这篇文章将为大家详细讲解有关怎么在mysql使用sql语句创建表,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1、语句说明可以使用CREATE TABLE语句创建表。允许NULL值,则说明在
2023-06-15

MySQL创建临时表的语句怎么写

在MySQL中,可以使用CREATE TABLE语句来创建临时表。临时表是一种在当前会话中存在,并在会话结束后自动删除的表。下面是创建临时表的语句格式:CREATE TEMPORARY TABLE table_name (column
MySQL创建临时表的语句怎么写
2024-04-09

编程热搜

目录