JS进行sql脚本整理

2023-11-04

JS进行sql脚本整理

在项目增量开发时,会出现开发环境因为集成了新功能或修改了旧功能,导致数据库中数据表字段修改或数据已经更新的情况。这时如果其他环境想要使用新功能,除了更新服务程序外,还需要将开发环境新增的数据整理成sql进行数据同步。

如果新增的数据量很大或者一次需要同时更新几张数据表数据的情况,手动整理是非常费力耗时的操作,而且很可能因为疏忽写错sql语法或者数据。

为了避免sql脚本整理错误,需要让机器帮忙进行sql脚本生成。本来想用Java来完成这个功能,但Java编码太繁琐了,所以这里选用NodeJS来完成。

  • NodeJS连接Mysql

    因为项目使用的SQL数据库是Mysql,所以NodeJS需要有连接Mysql并操作数据库的能力。这里官方提供了一个mysqljs,只需要通过 npm install mysql进入js项目即可:

    npm install mysql
    
    • js中引入mysqljs模块

      const Mysql = require('mysql');
      
    • 连接配置信息

      const conn = Mysql.createConnection({
              host: '127.0.0.1',//IP
              port: '3306',//端口号
              user: 'user',//用户
              password: 'password',//密码
              database: 'database'//数据库
          });
      
    • 连接

      conn.connect();
      
    • 查询

      查询示例:

      /**
       * @param {string} sql //查询的sql
       * @param {Array} options //占位符
       * @param {Function} callback //查询结果回调
       */
      conn.query(sql, options, (error, results, fields) => {
                  if (error) throw error;
                console.log(results);//返回查询结果
              });
      

      返回结果示例:

      //无数据
      []
      //有数据
      [ RowDataPacket {
          id: 363014473,
          name: 'sun',
        AGE: 'uid5866',
          Date: 2020-05-13T02:06:54.000Z,
        isrequired: null,
      } ]
      

      查询无数据时,返回空数组。有数据时,返回RowDataPacket数组,RowDataPacket对象属性与数据库中的字段名-字段值对应,并且字段名与Mysql中存储保持一致。

      通过js的typeof进行测试RowDataPacket对象的字段值类型对应大致如下:数字是number,字符串是string,日期和null是object。

    • 结束连接

      conn.end();
      
  • 字段值转化

    由于目的是为了将查询到的结果转化为sql语句,又根据上述查询返回的结果,字段名本身与Mysql中对应,并且类型已经是string,不需要进行加工,所以只需要将返回的字段值转化为正确的string值即可。

    const Moment = require('moment');//导入日期格式化模块,npm install moment
    /**
     * @param {*} e //字段值
     * @return {string} v
     */
    function toSqlValue(e) {
        let v = '';
        if (typeof (e) == 'string') {
            if (e.search(/'/) != -1)
                v += '"' + e + '"';//"'e'"
            else
                v += '\'' + e + '\'';//'e' 或 '"e"'
        } else if (typeof (e) == 'number') {
            v += e;//e
        } else if (typeof (e) == 'object') {
            if (e == null) {
                v += 'NULL';//NULL
            }else if(e instanceof Date){
                v += Moment().format('YYYY-MM-DD HH:mm:ss');//'YYYY-MM-DD HH:mm:ss'
            }
        }
        return v;
    }
    
  • INSERT语句生成

    Mysql中INSERT的语法大致如下:

    INSERT INTO `table_name` (`column1`,`column2`, ...) VALUES ('value1', 'value2', ...)
    

    INSERT语句生成比较简单,只需要遍历RowDataPacket对象,将属性依次填入column,将属性值转化后填入value即可。

    /**
     * @param {string} table //表名
     * @return {object} row //RowDataPacket对象
     */
    function insertSql(table, row){
        let sql = 'INSERT INTO `' + table + '`(';
        for (col in row) {
            sql += '\`' + col + '\`, ';
        }
        sql = sql.substring(0, sql.lastIndexOf(','));
        sql += ') VALUES (';
        for (col in row) {
            sql += toSqlValue(row[col]) + ', ';
        }
        sql = sql.substring(0, sql.lastIndexOf(','));
        sql += ');'
        return sql;
    }
    function bathInsertSql(table, rows){
        let sql = '';
        for (let i = 0; i < rows.length; i++) {
            sql += insertSql(table, rows[i]) + '\r\n';
        }
        return sql;
    }
    
  • UPDATE语句生成

    Mysql中UPDATE的语法大致如下:

    UPDATE `table_name` SET `column1` = 'value1',`column2` = 'value2', ... 
    WHERE `column1` = 'value1' AND `column2` = 'value2'
    

    UPDATE中的WHERE可能会有其他复杂情况,但目前本人没有遇到复杂的场景,所以只实习了上述的UPDATE语句生成。

    /**
     *
     * @param {string} table //表名
     * @param {Array} updateCols //更新字段
     * @param {object} row //RowDataPacket对象
     * @param {Array} whereCols //条件
     * @param {Array} whereConects //连接词
     */
    function updateSql(table, updateCols, row, whereCols, whereConects){
        let sql = 'UPDATE `' + table + '` SET ';
        for (let i = 0; i < updateCols.length; i++) {
            let col = updateCols[i];
            sql += '`' + col + '` = ' + toSqlValue(row[col]) + ', ';
        }
        sql = sql.substring(0, sql.lastIndexOf(','));
        if (whereCols == undefined) {
            sql += ';';
        } else {
            sql += '\r\n';
            sql += 'WHERE ';
            let wclen = whereConects.length;
            for (let i = 0; i < wclen; i++) {
                let col = whereCols[i];
                let con = whereConects[i];
                sql += '`' + col + '` = ' + toSqlValue(row[col]) + ' ' + con + ' ';
            }
            let col = whereCols[whereCols.length - 1];
            sql += '`' + col + '` = ' + toSqlValue(row[col]) + ';\r\n';
        }
        return sql;
    }
    
  • 创建mapper模块

    //mapper.js
    const mapper = {
        tableName:{
            getTableNameByID: `select * from table_name where id = ?`,
        	... ...
        },
        ... ...
    };
    
    module.exports = mapper;//模块导出
    
  • 创建table模块

    //table.js
    const table = {
        tableName: `table_name`,
        ... ...
    }
    
    module.exports = table;//模块导出
    
  • sql整理(只提供INSERT生成示例,UPDATE同理)

    利用上述提供的方法可以已经可以进行简单的sql整理了,如下:

    const Mysql = require('mysql');
    const fs = require('fs');
    const Util = require('./utils');//包含上述字段值转化、ISNERT和UPDATE语句生成方法
    const Table = require('./table');
    const Sql = require('./mapper');
    const Config = require('./config');//一些配置信息
    
    const conn = Mysql.createConnection(Config.mysql);
    conn.connect();
    let id = Config.tableName.id;
    conn.query(Sql.tableName.gettableNameByID, [id], (error, results, fields) => {
        if (error) throw error;
        let inserts = Util.bathInsertSql(Table.tableName, results);
        //生成sql文件
        fs.writeFile(Config.FILE_PATH, inserts, 'utf8', (err) => {
            if (err) throw err;
            console.log(`${Config.FILE_PATH}脚本生成完成`);
        });
        conn.end();//必须关闭,否则代码不会停止
    });
    

    !但是,对于一次需要同时更新几张表的情况,往往会出现一个查询语句的条件依赖于上一个查询语句的结果值。这时会出现query的回调中又嵌套着一个或者几个query,这时Mysql连接断开的时机不太好判断,代码会变得非常不好维护。

    conn.query(Sql.tableName1.gettableName1ByID, [id], (error, results, fields) => {
        if (error) throw error;
       	//生成脚本...
        ... ...
        for(let r in results){
            conn.query(Sql.tableName2.gettableName2ByName, [results[r][name]], (error, results, fields) => {
       		 if (error) throw error;
                //生成脚本...
                ... ...
    		});
        }
    });
    

    优化:

    JS中通过async关键字申明异步方法,async function fn(){},这类方法会将返回值封装为Promise对象作为返回。其中还有await关键字(需要在async方法中使用),代码执行值await处时,将会等待await的表达式执行结束后再往下执行,将异步代码转为同步执行。

    • 使用Promise对象对query方法改造

      Promise的回调函数有resolve和reject两个参数,resolve用于将内部异步方法执行完成后的需要的结果值传递至Promise对象,reject则是将代码错误传递至Promise对象。

      function query(sql, options) {
          return new Promise((resolve, reject) => {
              conn.query(sql, options, (error, results, fields) => {
                  if (error) throw reject(error);
                  resolve(results);
              });
          });
      }
      
    • 回调嵌套优化

      //将sql整理整合为一个方法
      async function generate(id, callback) {
          let inserts = '';
          let table1 = await query(Sql.tableName1.gettableName1ByID, [id]);//代码将会阻塞直到获得query结果
          inserts += `${Util.bathInsertSql(Table.tableName1, table1)}\r\n`;
          for(let r in results){
              let table2 = await query(Sql.tableName2.gettableName2ByName, [results[r][name]]);
              inserts += `${Util.bathInsertSql(Table.tableName2, table2)}\r\n`;
          }
          callback(inserts);
      }
      
      generate(ID, (res) => {
          conn.end();//这时只需要在方法执行结束后关闭连接即可
          fs.writeFile(Config.FILE_PATH, res, 'utf8', (err) => {
              if (err) throw err;
              console.log(`${Config.FILE_PATH}脚本生成完成`);
          });
      });
      
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JS进行sql脚本整理 的相关文章

随机推荐

  • [VS Code]-代码高亮设置

    代码高亮设置 在vscode 中对 选中的代码片段高亮颜色设置 和 所在当前行高亮提示设置 workbench colorCustomizations 2 写配置代码 workbench colorCustomizations editor
  • ThreadLocal从变量副本的角度解决多线程并发安全问题

    ThreadLocal从变量副本的角度解决多线程并发安全问题 之前我们讲的高并发场景下的线程安全问题 可以使用Synchronized同步关键字 Lock手动加锁的方式去解决 什么轻量级锁 偏向锁 重量级锁 可重入锁等等 实际上本质都是控制
  • Elasticsearch的long类型精准匹配异常?

    ES version 7 5 2 现象 通过其他字段可以查询出elasticsearch的doc数据 但通过某个long类型的字段精准匹配时不能hit GET index name search query term field value
  • 零基础上手定制谷歌浏览器插件

    文章目录 谷歌插件 核心内容简述 谷歌插件小案例 安装自定义谷歌插件 结语 谷歌插件 说起谷歌插件 相信大家应该都不陌生 比如下图就是我所安装的一些谷歌插件 而今天我所要做的不是给大家介绍有哪些好用的谷歌插件 而是给大家介绍一种快速上手自己
  • 懒汉模式的单例中对于指令重排序的规避方案

    1 双重检查的单例模式中可能会出现第一个非空判断为true 可是instance并没有初始化的情况 这种情况如果线程1去访问instance则会报异常 使用volatile关键字去声明instance可以规避2 3步的指令重排序 进而规避这
  • CMake入门指南

    CMake是一个比make更高级的编译配置工具 它可以根据不同平台 不同的编译器 生成相应的Makefile或者vcproj项目 通过编写CMakeLists txt 可以控制生成的Makefile 从而控制编译过程 CMake自动生成的M
  • python做excel自动化-Python如何控制Excel实现自动化办公

    Python如何控制Excel实现自动化办公 发布时间 2020 04 07 09 51 44 来源 亿速云 阅读 132 作者 小新 这篇文章主要给大家讲解的是Python如何控制Excel实现自动化办公 主要用到了xlsxwriter库
  • python画双坐标图_Python绘图分组双坐标柱状图(全网唯一,发布源代码),python,画,公布...

    目前在网络上没有找到现成的办法解决双坐标分组柱状图 为了画这个图 花了3小时 实现效果 源代码如下 import matplotlib pyplot as plt a 4 5 0 b 3 2 0 c 4 3 0 d 3 2 0 a 2 0
  • Hololens2项目基础开发

    目录 一 前言 二 VS2019负载安装 三 Hololens2项目环境配置 四 项目具体功能实现 五 打包部署真机测试 一 前言 Hololens2项目基础开发包含 单 双 手近距离控制物体移动旋转 双手近距离控制物体的缩放 语音功能 控
  • MATLAB中的corrcoef函数求两个向量的相关系数。

    想用MATLAB中的corrcoef函数求两个向量的相关系数 比如A 1 2 3 B 5 3 7 r corrcoef A B 可以求出相关系数是0 5 为什么两个向量的元素都要是3个以上才行 而只有两个元素的向量如A 1 2 B 5 3
  • 计算机网络笔记第二章链路层

    二 链路层和局域网 提供服务 差错检测error detection correction 共享广播信道sharing a broadcast channel 多路访问multiple access 多通信同时进行同一段链路如何使用 链路层
  • PHP之 导入excel表格时,获取日期时间变成浮点数

    读取到的时间 float 0 20833333333333 原格式 15 00 00 代码 if Request isPost file url input upfile 本地上传文件地址 读取文件内容 local file url dir
  • vsftpd下错误之:500 OOPS

    vsftpd下错误之 500 OOPS vsftpd 是在Linux发行版中最推崇的一种FTP服务器程序 vsftpd的特点 小巧轻快 安全易用等 Linux也是为人们所常用的操作系统之一 这里主要讲的是如何解决vsftpd下错误之 500
  • 信捷 XD3 PLC+TG465-XT HMI开箱

    PLC 新到手了一台信捷 XD3 60RT E 这是我摸过的继西门子 三菱之后的第三个牌子 也是第一个国产品牌 打开包装盒的第一个感觉是这台机型简直和停产多年的三菱 FX2N一模一样 就是不清楚它具体是和三菱哪个机型对标的 变化还是有的 用
  • go-zero 基础

    官网 github 开发规范 1 环境准备 1 1 goctl安装 1 2 protoc protoc gen go安装 方式一 goctl env check i f verbose 方式二 源文件安装 2 快速开始 本节主要通过对 ap
  • 误操作清空了回收站文件如何找到文件

    我们在删除文件的时候 文件都是先跑到回收站里的 这样的防止我们出现误删的情况 但往往也会出现我们要恢复删除的文件却误操作清空了回收站的情况 那么误操作清空了回收站如何找到呢 下面小编给大家分享误操作清空了回收站文件找到的方法 误操作清空了回
  • 计算样本方差时为什么除以(n-1)

    方差概念 除以n其实没错 但只适用于母体方差 总体均数已知 同样的 样本标准差也只适用于样本方差 让我们看一下这两个公式 统计学重要的研究内容之一是 用样本推测总体 具体而言 就是用样本均数和样本标准差来估计总体均数和总体标准差 而这里的估
  • 如何利用maven配置mybatis-generator自动生成mapper.xml

    首先配置pom xml文件 新增插件
  • 散点图绘制

    文章目录 1 二维数组的索引 2 npz文件 3 散点图的绘制 在Python数据分析与应用中有一个散点图的例子 做这个例子之前首先要弄清楚两个点 对二维数组进行取数操作 python中的npz文件 1 二维数组的索引 二维数组中的每一个元
  • JS进行sql脚本整理

    JS进行sql脚本整理 在项目增量开发时 会出现开发环境因为集成了新功能或修改了旧功能 导致数据库中数据表字段修改或数据已经更新的情况 这时如果其他环境想要使用新功能 除了更新服务程序外 还需要将开发环境新增的数据整理成sql进行数据同步