91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

MySQL建表語句轉PostgreSQL建表語句全紀錄

發布時間:2020-07-12 13:43:00 來源:網絡 閱讀:851 作者:lilizhou2008 欄目:數據庫

個人習慣用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語句。

為什么不改進?因為沒有時間,工具是為工作服務的,目前能達到我的目的,就沒動力修改了,未來有需求再改進吧。

原文

http://www.itmuch.com/work/mysql-ddl-2-pgsql-ddl/ ,轉載請說明出處。

干貨分享

MySQL建表語句轉PostgreSQL建表語句全紀錄

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

渝北区| 蓝田县| 筠连县| 九台市| 陵水| 全椒县| 佳木斯市| 丰城市| 南召县| 宿松县| 宁河县| 洛隆县| 古丈县| 葵青区| 韩城市| 晋州市| 仪征市| 邓州市| 新安县| 石河子市| 探索| 临洮县| 北川| 思南县| 衡南县| 灵川县| 通榆县| 岳池县| 蒙阴县| 嘉善县| 宁河县| 德江县| 光泽县| 杂多县| 博兴县| 阿合奇县| 濮阳市| 天全县| 东阳市| 神农架林区| 广丰县|