JS 实现CSV文件转换SQL文件小工具

一. 需求

最近在项目中遇到一个问题,客户提供的数据是CSV格式的,
需要将CSV文件中的数据转换为SQL语句文件。

😅由于本人不会Excel的vba编程,因此决定使用JS来实现。


二. 实现思路

  • 提供一个文件上传框,支持多文件上传,且只能上传csv文件
  • 使用new FileReader()来读取上传的csv文件
  • 每个csv文件都包含标题栏,因此需要从第二行开始读取数据
  • 将读取到的数据构造成insert的sql语句然后存放到一个list中
  • 创建Blob对象,将包含sql的list放入该对象中构建sql文本对象
  • 通过URL.createObjectURL()获取Blob对象在内存中的地址
  • 创建a标签,配合内存中的地址实现sql文件下载

三. CSV文件例子

"CQ企画番号","共同購入商品コード","CQ商品コード","JANコード","定催区分","部門コード","大分類","中分類","小分類","集品区分","商品名漢字","規格名漢字","入数","納品時容器区分","シール貼付有無区分","資材名","税抜組合員単価","税込組合員単価","企画年月回","配達年月回","企画単協 エフ","企画単協 さが","企画単協 ララ","企画単協 おおいた","企画単協 水光社","企画単協 みやざき","企画単協 かごしま","企画単協 おきなわ","税コード","消費税率","単価計算区分","税抜計算区分","税込計算区分","禁則チェック区分","エラーコード","削除フラグ","作成日","作成時刻","更新日","更新時刻"
"301","1005405","100317290","2000000432908","1","02","01","02","09","02","フレンドリーバナナ(フィリピン産)","750g",1,"2","0",,288,311,"2023041","       ","0","0","0","0","0","0","0","1","080",0.08,"2","2","1","1","  ","0","20230117","100742","20230309","102624"
"301","1039130","100499798","2000000648941","1","02","01","02","09","02","フレンドリーバナナ(フィリピン産)","500g(3?5本)",1,"2","0",,278,300,"2023041","       ","0","0","0","0","0","0","0","1","080",0.08,"2","2","1","1","  ","0","20230117","100742","20230309","102624"
"301","1355180","800022912","2008000229122","1","01","01","01","02","02","貝割大根(大分県産)","1パック",20,"2","0",,36,38,"2023041","       ","0","0","0","1","0","0","0","0","080",0.08,"2","2","1","1","  ","0","20230117","100742","20230309","102624"
"301","1395165","800055699","2000000678788","1","01","01","00","05","02","たまねぎ(北海道産)","300g(大小混)",1,,"0",,138,149,"2023041","       ","0","0","0","0","0","0","0","1","080",0.08,"2","2","1","1","  ","0","20230117","100742","20230309","102624"
"301","1409182","100433518","2000000601557","2","01","01","00","05","00","よくねたいも〈北あかり〉(北海道産)","500g(大小混)",1,"1","0",,258,278,"2023041","       ","0","0","0","0","0","0","0","1","080",0.08,"2","2","1","1","  ","0","20230302","130441","20230309","102458"
"301","1417550","800072337","2008000723378","1","01","01","00","01","05","ほうれん草(長崎県産)","150g",1,"2","0",,138,149,"2023041","       ","0","0","1","0","0","0","0","0","080",0.08,"2","2","1","1","  ","0","20230117","100742","20230309","102624"

四. 转换工具

  • 复制代码创建html文件,拿来就用。😋不用配置环境
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSV转换SQL工具</title>
</head>
<body>
    <div style="display: flex;">
        <label for="schema">指定schema</label>
        <select id="schema">
            <option value=""></option>
            <option value="nosan">nosan 农业</option>
            <option value="sozai">sozai 蔬菜</option>
            <option value="shokan">shokan 商管</option>
        </select>
    </div>
    <hr>

    <label for="removeBlank">是否去除字符串中的空白</label>
    <input id="removeBlank" type="checkbox" />
    <hr>

    <label for="csv">请上传csv文件</label>
    <input id="csv" type="file" accept=".csv" multiple />
    <hr>

    <button id="transform">csv转sql开始</button>
    <hr>

    <!-- 显示错误消息的区域 -->
    <div id="error" style="color: red;">
        
    </div>
</body>
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script>
    // 是否去除字符串空白flag
    let removeBlank = false;

    $(function() {
        transformEvent();
    });

    function transformEvent() {

        $("#transform").click(function() {

            removeBlank = $("#removeBlank").prop("checked");

            const schema = $("#schema").val();
            if(!schema) {
                alert("请指定schema!");
                return;
            }

            // 清空所有的内容
            $("#error").empty();

            // 获取上传的所有csv文件
            const csvFileList = $("#csv").get(0).files;
            for(csvfile of csvFileList) {

                const sqlList = [];

                /*
                    将上传的文件名称当做表名
                    注意:
                        下面这行代码不能放到reader的load回调里面,
                        否则生成的csv的文件名会相同
                */
                const tableName = csvfile.name.split(".")[0];
                
                // 创建csv文件读取对象
                const reader  = new FileReader();

                // 指定要读取的CSV的编码
                reader.readAsText(csvfile, "Shift_JIS");
                reader.addEventListener('load', ({target: {result: csvText}}) => {

                    // 获取出标题栏之外的csv内容数据
                    const hanleCSVData = csvText.slice(csvText.indexOf('\n') + 1).split('\n');

                    // 如果上传的csv文件只有标题没有数据
                    if(!hanleCSVData || hanleCSVData.length === 1 && !hanleCSVData[0].trim()) {
                        const newHtml = $("#error").html() + "<br />" + tableName + ".csv文件没有内容!";
                        $("#error").html(newHtml);
                        return;
                    }

                    for (const csvRowData of hanleCSVData) {

                        if (!csvRowData) {
                            continue;
                        }

                        // 构造插入SQL
                        let insertSql = SqlUtils.createBaseSql(schema, tableName);
                        
                        // 创建要插入sql的值
                        const sqlValueStr = SqlUtils.addCsvRowToSqlItem(csvRowData);
                        
                        // 补足自定义项目后,构建
                        const insertSqlStr = SqlUtils.customeSqlHandle(insertSql + sqlValueStr);

                        sqlList.push(insertSqlStr);
                    }

                    // 下载转换之后的sql文件
                    fileDownload(sqlList, `${tableName}.sql`);
                });
            }
        });
    };

    class SqlUtils {

        // 获取当前时间 yyyy/MM/dd HH:mm:ss
        static nowDate = new Date().toLocaleString();

        // 是否去除字符串中的空白
        static trimStrFlg = true;

        // 创建基本的插入SQL语句
        static createBaseSql(schema, tableName) {
            // 因为csv项目和表项目完全一致,因此可以省略项目
            return `INSERT INTO [${schema}].${tableName} VALUES (`;
        }

        static addCsvRowToSqlItem(csvRowData) {

            let sqlItem = "";
            // 获取CSV所有的列
            const csvItemList = csvRowData.split(",");
            const newcsvItemList = [];

            // 对csv项目进行特殊处理
            for (const csvItem of csvItemList) {
                if(!!csvItem) {
                    /*
                        如果需要去除空格,并且是csv中的字符串项目的话
                    */
                    if (removeBlank && csvItem.includes("\"")) {
                        // "测试     "   ===> '测试'
                        newcsvItemList.push("\'" + csvItem.replaceAll('"', '').trim() + "\'");
                    } else {
                        // 插入的是数字
                        newcsvItemList.push(csvItem);
                    }

                } else {
                    // 如果csv项目为空项目则插入NULL
                    newcsvItemList.push('NULL');
                }
            }

            // 将list转换为以 , 分隔的字符串,并把 " 替换为 ' ,因为sql插入时只能用 '
            return newcsvItemList.join(", ").replaceAll('\"', '\'') + ", ";
        }

        static customeSqlHandle(insertSql) {
            // 插入时间
            const SKSI_NCHJ = `'${SqlUtils.nowDate}'`;
            // 更新时间
            const KUSHN_NCHJ = `'${SqlUtils.nowDate}'`;

            // 添加换行符
            return `${insertSql}${SKSI_NCHJ}, ${KUSHN_NCHJ});\r\n`;
        }
    }

    function fileDownload(data, fileName) {

        // 创建文件下载的url
        const insertSqlStrBlob = new Blob(data, {type: "application/sql"});
        const src = URL.createObjectURL(insertSqlStrBlob);

        // 创建a标签
        const aElement = document.createElement('a');
        aElement.download = fileName;
        aElement.style.display = 'none';
        aElement.href = src;

        // 将a标签添加到页面上手动触发点击事件,从而触发文件下载
        document.body.appendChild(aElement);
        aElement.click();
        document.body.removeChild(aElement);

        URL.revokeObjectURL(src);
    }
</script>
</html>

五. 效果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值