excel转mysql 工具_一个简单的批量excel转mysql工具
背景:工作中,经常发现需要将excel中的表数据导入到mysql中,实际操作一般都是用navcat,但是使用中也发现navcat只支持单个表导入,对xlsx格式支持不友好。于是写了这么一个导表工具。在此,重新记录一下过程。
先说一下结果:
1. 支持批量文件导入
2. 目前只支持单个数据库导入,稍微改动一下可以支持多个数据库
3. 只支持xlsx格式,改动下可以支持xls格式
效果大概是这样
过程如下:
一:设计前端页面
这个我不是很懂,多年来对前端江湖不敢入。只会一些js操作, css那一块完全不懂。所幸导表工具不需要很复杂的页面,只需要一个简单的上传按钮就可以了,网上找一些页面,简单修改下即可使用,这个略去
二:服务端设计
先说一下具体思路
先将excel文件上传到服务器
服务器解析文件得到sql文件
写入sql文件
项目目录如下
其中,main.go是启动文件, www目录下是静态文件,excel2db_app.go包含一个Start方法,excel2db包含主要逻辑。
下载必须的类库,直接用go get命令即可,主要是这两个
"github.com/go-sql-driver/mysql"
"github.com/tealeg/xlsx"
main.go文件,直接调用excel2db_app.go的Start()方法即可,这里略去
excel2db_app.go文件,
主要代码如下
package excel2db
import (
"fmt"
"mime/multipart"
"net/http"
//"os"
//"io"
"html/template"
"log"
//"time"
"io/ioutil"
"strconv"
"strings"
)
func upload(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
if r.Method == "GET" {
t, err := template.ParseFiles("./app/excel2db/www/input_sql.html")
checkErr(err)
t.Execute(w, nil)
} else {
r.ParseMultipartForm(32 << 20)
mp := r.MultipartForm
if mp == nil {
log.Println("not MultipartForm.")
w.Write(([]byte)("不是MultipartForm格式"))
return
}
go action(w, mp)
}
}
func action(w http.ResponseWriter, mp *multipart.Form) {
fhs := mp.File["file"]
num := len(fhs)
log.Printf("总文件数:%d\n", num)
for n, fheader := range fhs {
fmt.Printf("%d : %s\n", n, fheader.Filename)
if !strings.HasSuffix(fheader.Filename, ".xlsx") {
continue
}
uploadFile, err := fheader.Open()
checkErr(err)
data, err := ioutil.ReadAll(uploadFile)
checkErr(err)
// defer func() {
// if e := recover(); e != nil {
// fmt.Printf("Panicing %s\r\n", e)
// }
// }()
readExcelFile(data)
}
w.Write(([]byte)("成功"))
log.Println("upload success")
}
func checkErr(err error) {
if err != nil {
// err.Error()
log.Println(err)
}
}
func Start() {
fmt.Println("----Excel to Sql multiple工具启动中----")
http.Handle("/js/", http.FileServer(http.Dir("app/excel2db/www/")))
http.Handle("/css/", http.FileServer(http.Dir("app/excel2db/www/")))
http.HandleFunc("/upload", upload)
port := 8888
log.Println("欢迎使用 http://127.0.0.1:" + strconv.Itoa(port) + "/upload")
err := http.ListenAndServe(":"+strconv.Itoa(port), nil)
if err != nil {
log.Fatal("listenAndServe: ", err)
}
}
可以看到,就是启动了一个http服务器
excel2db.app文件,代码如下
package excel2db
import (
"bytes"
"database/sql"
"fmt"
"log"
_ "strconv"
"strings"
_ "strings"
_ "github.com/go-sql-driver/mysql"
"github.com/tealeg/xlsx"
)
const user_name = "zjs"
const password = "123456"
const db_url = "127.0.0.1:3306"
const db_name = "ddd2h5_dev"
func excelToDb(fileNames []string) {
// 先将Excel读取
for _, fname := range fileNames {
fmt.Println("====", fname)
xlFile, err := xlsx.OpenFile(fname)
checkErr(err)
for _, sheet := range xlFile.Sheets {
tbName := sheet.Name
fmt.Println("表名:", tbName)
var buffer bytes.Buffer
buffer.WriteString("insert into ")
buffer.WriteString(tbName)
for rowIndex, row := range sheet.Rows {
if rowIndex == 1 {
buffer.WriteString(" (")
for _, cell := range row.Cells {
// 0行是中文解释, 1行是字段名
text := cell.String()
fmt.Printf("%s\n", text)
buffer.WriteString(text)
buffer.WriteString(",")
}
buffer.WriteString(")")
}
}
}
}
}
func readExcelFile(data []byte) {
xlFile, err := xlsx.OpenBinary(data)
checkErr(err)
tabMap := getAllTables()
for _, sheet := range xlFile.Sheets {
tbName := sheet.Name
_, isExist := tabMap[tbName]
if !isExist {
continue
}
fmt.Println("表名:", tbName)
colMap1 := make(map[string]int) // 当成一个set, 判断是否存在column
colMap2 := make(map[int]string) // 真正的map,得到位置与column的关系
// 根据表名得到栏目名,一般情况下excel会比db表多出一些字段
err := getColumnName(tbName, colMap1)
if err != nil {
log.Println("查找表报错-----", tbName)
log.Println(err)
continue
}
var buffer bytes.Buffer
buffer.WriteString("insert into ")
buffer.WriteString(tbName)
buffer.WriteString(" (")
var findColumnOver = false
var lastColNumber = -12
for _, row := range sheet.Rows {
// 直接循环,直到碰到与栏目名对应的那一行
if !findColumnOver {
for index, cell := range row.Cells {
text := cell.String()
_, exist := colMap1[text]
if exist {
colMap2[index] = text
buffer.WriteString("`")
buffer.WriteString(text)
buffer.WriteString("`")
if len(colMap1) == len(colMap2) {
findColumnOver = true
lastColNumber = index
buffer.WriteString(") values ")
} else {
buffer.WriteString(",")
}
}
}
if len(colMap2) != len(colMap1) {
//数据不相等,栏目名找错了,直接清空
colMap2 = make(map[int]string)
buffer.Reset()
buffer.WriteString("insert into ")
buffer.WriteString(tbName)
buffer.WriteString(" (")
}
} else {
// 说明这时可以导数据了
isBlankColumn := false
for ind, cell := range row.Cells {
_, exist := colMap2[ind]
if !exist {
continue
}
text := cell.String()
if ind == 0 && strings.Compare(text, "") == 0 {
// 空白数据
isBlankColumn = true
break
}
if ind == 0 {
buffer.WriteString("(")
}
buffer.WriteString("\"")
buffer.WriteString(text)
buffer.WriteString("\"")
if ind == lastColNumber {
buffer.WriteString(")")
break
} else {
buffer.WriteString(",")
}
}
// 判断是否还有其他数据
if len(row.Cells) != 0 && !isBlankColumn {
buffer.WriteString(",")
}
}
}
str := buffer.String()
sql := str[0 : len(str)-1] // 把','去掉
//log.Println("jieguo: ", sql)
// 先清空表数据
clearTable(tbName)
// 插入新数据
insertToDb(sql)
}
}
var MY_DB *sql.DB = nil
func getDb() *sql.DB {
if MY_DB == nil {
//db, err := sql.Open("mysql", "zjs:123456@tcp(127.0.0.1:3306)/ddd2h5_dev?charset=utf8")
db, err := sql.Open("mysql", user_name+":"+password+"@tcp("+db_url+")/"+db_name+"?charset=utf8")
if err != nil {
log.Fatal("数据库链接出错: ", err)
}
//checkErr(err)
MY_DB = db
}
return MY_DB
}
func getAllTables() map[string]int {
tabMap := make(map[string]int)
rows, err := getDb().Query("show tables")
if err != nil {
log.Println("得到全部表名报错:", err)
}
for rows.Next() {
var tabName string
rows.Scan(&tabName)
tabMap[tabName] = 0
}
return tabMap
}
func getColumnName(tbName string, colMap map[string]int) error {
rows, err := getDb().Query("select * from " + tbName + " limit 1")
if err != nil {
return err
}
//返回所有列
cols, _ := rows.Columns()
for _, col := range cols {
colMap[col] = 0
}
return nil
}
func clearTable(tbName string) {
_, err := getDb().Exec(" DELETE FROM " + tbName)
if err != nil {
log.Println("清空表报错: ", err)
}
}
func insertToDb(sql string) {
_, err := getDb().Exec(sql)
if err != nil {
log.Println("插入数据报错:", err)
}
}
excel转mysql 工具_一个简单的批量excel转mysql工具相关推荐
- php使用mysql怎么连接浏览器_一个简单的php实现的MySQL数据浏览器
一个简单的php实现的MySQL数据浏览器 更新时间:2007年03月11日 00:00:00 作者: 这个程序可以用来浏览MySQL中的数据,您可以稍做修改就可以做出很不错的MySQL浏览器. ...
- php简单的mysql类_一个简单的php mysql操作类
本文分享一个简单的php.mysql操作类,很简单,主要是数据的连接.查询等.有需要的朋友参考下吧. 分享一段php.mysql操作类的代码,供初学的朋友参考. 一个简单的类使用php和mysql数据 ...
- mysql浏览器_一个简单的MySQL数据浏览器
一个简单的MySQL数据浏览器 更新时间:2006年10月09日 00:00:00 作者: 这个程序可以用来浏览MySQL中的数据,您可以稍做修改就可以做出很不错的MySQL浏览器. */ /* ...
- php+mysql记事本_一个简单记事本php操作mysql辅助类创建
//SqlHelper.class.phpconn=mysql_connect($this->host,$this->user,$this->passwrd); if(!$this- ...
- mvc登录实例 mysql_spring mvc + mybatis + mysql 调整的一个简单的登录例子
spring mvc + mybatis + mysql 整合的一个简单的登录例子 今天用spring跟mybatis整合写了一个简单的登录例子,第一次整合,给自己做个笔记,可能注释写的有点少,做的不 ...
- 用计算机制作动画,如何使用制作工具制作一个简单的Flash动画-电脑自学网
怎么制作Flash动画?通过Adobe Flash我们可以制作出非常有趣好看的动画,也可以制作一键简单的小动画,下面给大家介绍如何使用制作工具制作一个简单的Flash动画. 操作方法: 1.打开fla ...
- Matlab中如何使用appdesigner设计工具建立一个简单的界面
Matlab中如何使用appdesigner设计工具建立一个简单的界面(数据的输入.处理和保存) 以使用不同算法处理图像的功能为例 建立一个新的空白界面,matlab中输入appdesigner,打开 ...
- 如何实现一个简单好用的roadmap制作工具
周末实现的一个简单好用的roadmap制作工具, https://fancylife.github.io/z-roadmap/ ,开源给大家
- [RK3288][Android7.1]在Root用户下的一个简单更改开机动画的小工具
[RK3288][Android7.1]在Root用户下的一个简单更改开机动画的小工具 Platform: Rockchip OS: Android 7.1.2 Kernel: 4.4 需求: 在使用 ...
最新文章
- UIMenuController的简单使用
- python数字编码_Python 编码为什么那么蛋疼?
- nginx 中location中root和alias的区别
- arduino char*转string_Java 中 String 类的常用方法汇总
- excel批量更改超链接_批量新建Excel指定名称工作表并设置超链接!你,学会了吗?...
- 网站集成QQ登录功能
- ubuntu-16.04安装程序报错 you might want to run 'apt-get -f install' to correct these
- 复制pdf文本出现大量换行的解决办法
- 渗透工具——Namp基础用法
- MFC绘制bmp图片背景
- B75经典门户商业版Discuz模板下载
- 微信小程序自定义picker
- Chrome打包扩展程序错误,清单文件缺失或不可读
- 微信商户平台结算周期T+1是什么意思
- 集合转换成数组的两种方法---toArray()和toArray(T[] a)
- [JZOJ5710] Mex
- 移动CRM产品同质化严重,市场一片红海
- java选择题《每日一练》
- 爆糗的买单,看谁脸皮厚
- 2013的联想台式计算机,联想台式电脑选购常识_联想台式电脑使用常识 -真快乐商城...