本程序主要用於遊戲編程等相關項目中,產品人員使用excel設計數據之後直接將相關數據生成sql,可以導入數據庫
excel格式及相關的使用方法,請下載數據包http://download.csdn.net/download/wentianyao/9401274
該庫使用了luacom組件所以只能在windows使用
-- excel文件解析成sql文件
-- ws
-- 2015.5
------------------------------------------------------------------------
--配置部分
-- 生成sql目標文件的前綴
local FilePrefix = "conf_"
-- 識別excel中表的前綴
local TablePrefix = "conf_"
------------------------------------------------------------------------
-- 加載庫文件
package.path=package.path..";..\\?.lua;..\\..\\scripts\\?.lua"
require("luacom")
require("json")
local lfs = require"lfs" -- 加載文件處理庫
------------------------------------------------------------------------
local exl2sql={}
-- 設置類型長度 語句配置
-- 數據類型 創建表的時候用(屬性創建語句) 數據爲空的時候的替換數據
exl2sql.STRINGTYPE ={["UINT11"] = {"int(11) unsigned NOT NULL DEFAULT '0'", 0},
["INT11"] = {"int(11) NOT NULL DEFAULT '0'", 0},
["INT32"] = {"int(32) NOT NULL DEFAULT '0'", 0},
["INT64"] = {"int(64) NOT NULL DEFAULT '0'", 0},
["STRING32"] = {"varchar(32) DEFAULT NULL", "\'\'"},
["STRING64"] = {"varchar(64) DEFAULT NULL", "\'\'"},
["STRING128"] = {"varchar(128) DEFAULT NULL", "\'\'"},
["STRING256"] = {"varchar(256) DEFAULT NULL", "\'\'"},
["STRING512"] = {"varchar(512) DEFAULT NULL", "\\'\''\'"},
["STRING1024"] = {"varchar(1024) DEFAULT NULL", "\'\'"},
["STRING2048"] = {"varchar(2048) DEFAULT NULL", "\'\'"},
["DATETIME"] = {"datetime default '0000-00-00 00:00:00'", "\'\'"},
["JSON256"] = {"varchar(256) DEFAULT NULL", "\'\'"},
["JSON1024"] = {"varchar(1024) DEFAULT NULL", "\'\'"},
["JSON2048"] = {"varchar(2048) DEFAULT NULL", "\'\'"}}
-- 字符串的處理“^%s”表示匹配所有非s裏面的數據,*表示匹配前一個字符串0次或多次,(.-)表示匹配.或者-,%s*表示0次或多次匹配s
function exl2sql.trim(s)
return s:match "^%s*(.-)%s*$"
end
-- 將字符串s中的符合tMode的子串替換爲tReplace
function exl2sql.escape(s)
local tMode="[%z\'\"\\\26\b\n\r\t]"
local tReplace={
['\0']='\\0',
['\'']='\\\'',
['\"']='\\\"',
['\\']='\\\\',
['\26']='\\z',
['\b']='\\b',
['\n']='\\n',
['\r']='\\r',
['\t']='\\t'
}
return string.gsub(s, tMode, tReplace)
end
-- 獲取目標目錄下的有所*.xlsx文件
-- 參數path:爲純路徑
function exl2sql.GetAllXlsxFile(path)
local FileList = {}
local NoSuffixFileList = {} -- 無後綴的文件列表
-- 循環遍歷
for ofile in lfs.dir(path) do
if ofile ~= nil then
-- 獲取文件屬性
local f = path..'\\'..ofile
--local f = ofile
-- 拆分文件及後綴
local ext = f:match(".+%.(%w+)$")
-- 獲取本目錄下的所有的xlsx文件
if ext == "xlsx" then
-- 排除過度文件
local filename = string.sub(ofile, 0, 2)
if filename ~= "~$" then
table.insert(FileList, f)
local name = string.sub(f,0,f:match(".+()%.%w+$")).."sql" -- 生成的文件名
table.insert(NoSuffixFileList, name)
end
end
end
end
return FileList, NoSuffixFileList
end
-- 獲取文檔中每個sheet信息
-- 參數:ExlObj表示創建的Excel對象,BookObj表示打開的excel對象
-- 返回值: 返回所有有效的sheet列表,否則返回nil
function exl2sql.GetSheetInfo(ExlObj, BookObj)
-- 遍歷文件中的sheet標籤(目前暫定標籤格式爲TablePrefix指定),其他的不識別
local SheetList = {} -- 目標文件所有的sheet信息
-- 獲取sheet文件數量
local temp = BookObj.Sheets.Count
-- 遍歷所有的表名(excel中默認的起始編號是1)
for i = 0,(temp - 1) do
-- 獲取該table的數據特徵(列名,類型)
local tSheet=BookObj.Sheets(i + 1) -- 獲取當前的sheet文件
local tabname = ExlObj.ActiveWorkbook.Sheets(i+1).Name -- 獲取sheet名
-- 識別是不是要生成的TablePrefix指定的前綴表
local TablePrefixLen = string.len(TablePrefix) -- 獲取指定前綴的長度
local PreTabeName = string.sub(tabname, 0, TablePrefixLen) -- 截取sheet名字的前n個用於識別是不是前綴
-- 如果是要符合規範的sheet文件
if PreTabeName == TablePrefix then
-- 獲取sheet的屬性(編號及名字)
local tabattr = {TableIndx = nil, TableName = nil, ColList = {}} -- 表的基礎結構(表編號,sheet名字,表中所有有效列的信息)
tabattr.TableIndx = i + 1 -- 當前表所在的sheet編號
tabattr.TableName = tabname -- sheet對應的將要生成的name
tabattr.ColList = {}
print("INFO_1: read sheet"..tabattr.TableIndx.." :name".. tabname.. " base info start...")
-- 遍歷列,獲取列名(注:excel表中的必需第二行是列名)
local bBreak = true -- 跳出中斷
local ColNum = 1 -- 列編號
while bBreak == true do
local SheetInfo = {} -- 表的列信息(列編號,列名說明,列名,列類型)
SheetInfo.ColIndex = ColNum
SheetInfo.ColNameText = tostring(tSheet.Cells(1, ColNum).Value2) -- 獲取列名備註
SheetInfo.ColName = tostring(tSheet.Cells(2, ColNum).Value2) -- 獲取列名
SheetInfo.ColType = tostring(tSheet.Cells(3, ColNum).Value2) -- 獲取目標列的數據類型
-- 索引結束
if SheetInfo.ColName == "nil" then
print("INFO_2: the sheet: "..tabattr.TableName.." has check end...")
bBreak = false -- 循環中斷
break
end
if SheetInfo.ColType == "nil" then --缺少列類型
print("ERROR_1: this sheet: "..tabattr.TableName.." NO."..SheetInfo.ColIndex.." column have not Type!")
return nil --end
else
-- 類型檢查
if exl2sql.STRINGTYPE[SheetInfo.ColType] == nil then
print("ERROR_2: this sheet: "..tabattr.TableName.." NO."..SheetInfo.ColIndex.." column type is wrong!")
return nil
end
print("INFO_3: NO."..ColNum.." column".." Name: "..SheetInfo.ColName.." Type:"..SheetInfo.ColType)
-- 將列信息添加到表信息中
table.insert(tabattr.ColList, SheetInfo)
ColNum = ColNum + 1 -- 列編號+1
end
end -- while bBreak do
-- 提示信息
if table.getn(tabattr.ColList) == 0 then
print("ERROR_3: Have no any data from sheet"..ColNum.."!")
else
-- 表信息插入sheet列表
table.insert(SheetList, tabattr)
end
end -- if PreTabeName == TablePrefix then
end -- for i = 0,(temp - 1) do
-- 檢查SheetList是否爲空
if 0 >= table.getn(SheetList) then
return nil
end
-- 返回sheet列表
return SheetList
end
-- 根據列類型獲取數據
-- 參數:ColType表示列類型,Data表示列原始數據
function exl2sql.GetDataByType(ColType, Data)
-- 若讀取的數據爲空
if Data == nil then
local nildata = exl2sql.STRINGTYPE[ColType][2] -- 獲取數據爲空的時候的替換數據
return nildata
end
-- 若有數據
local bData = nil
if ColType == "UINT11" or ColType == "INT11" or ColType == "INT32" or ColType == "INT64"then
bData = tonumber(Data)
else
bData = exl2sql.trim(tostring(Data))
end
-- 特殊處理
-- 特殊處理1,json類型處理規則
local TypeSuf = string.sub(ColType, 0, 4) -- 獲取類型前4個,識別是不是json
if TypeSuf == "JSON" then
bData = exl2sql.escape(json.encode(json.decode(bData)))
end
-- 對於字符串加"“”"處理
if ColType == "UINT11" or ColType == "INT11" or ColType == "INT32" or ColType == "INT64"then
else
bData = "\""..bData.."\""
end
return bData
end
-- 執行sql的創建,包括表的創建和數據的插入
-- 參數:ExlObj表示創建的Excel對象,BookObj表示打開的excel對象,SheetObj表示已經檢查過的有效的sheet,WriteOutFile輸出的sql文件句柄
function exl2sql.CreateSql(ExlObj, BookObj, SheetObj, WriteOutFile)
-- 創建表的過程(獲取執行語句)
local tCreateSql = ""
local tNameList = {} -- 列名列表
local tNameType = {} -- 列類型
for i, ColInfo in ipairs(SheetObj.ColList) do
-- 根據類型獲取語句
local TypeString = exl2sql.STRINGTYPE[ColInfo.ColType][1] -- 獲取對應的類型長度
tCreateSql = tCreateSql .. "`"..ColInfo.ColName.."` "..TypeString
table.insert(tNameList, ColInfo.ColName)
table.insert(tNameType, ColInfo.ColType)
end
-- 獲取數據同時進行數據檢查
-- 提供主鍵檢查
local tSheet=BookObj.Sheets(SheetObj.TableIndx) -- 獲取當前的sheet文件
-- 遍歷所有數據(*目前從第4行開始)
local bBreak = true
local RowlIndex = 4 --遍歷的數據行(目前是從第4行開始)
local ColNumMax = table.getn(tNameList) -- 獲取有多少數據列
local RowKeyList = {} -- 所有主鍵值
local RowDataList = {} -- 所有行數據
while bBreak do -- 一直循環遍歷所有數據
local RowData = {} -- 行數據
-- 獲主鍵數據
local keydata = tSheet.Cells(RowlIndex, 1).Value2
if keydata == nil then -- 認爲數據結束
bBreak = false
break -- 中斷
end
-- 轉換成有效數據
local colKeydata = exl2sql.GetDataByType(tNameType[1], keydata)
-- 主鍵檢查
if RowKeyList[colKeydata] ~= nil then -- 表示該主鍵已經被用過了
-- 如果聯繫的兩個值都爲
print("ERROR_4: in sheet"..SheetObj.TableName.." DOUBLE PRIMARY KEY value:"..colKeydata) return nil
end
-- 插入主鍵
RowKeyList[colKeydata] = 1 -- 表示該主鍵已經使用
-- 插入第列數據
table.insert(RowData, colKeydata)
-- 其他數據
for j = 2, ColNumMax do
-- 獲取列數據
local coldata = exl2sql.GetDataByType(tNameType[j], tSheet.Cells(RowlIndex, j).Value2)
table.insert(RowData, coldata)
end
-- 加入數據列
table.insert(RowDataList, RowData)
RowlIndex = RowlIndex + 1 -- 行遞增
end
-- 插入註釋
WriteOutFile:write("\n\n-- -----------------------------\n-- "..SheetObj.TableName.."\n-- -------------------------------")
-- 插入表頭
WriteOutFile:write("\nDROP TABLE IF EXISTS `"..SheetObj.TableName.."`; \nCREATE TABLE `"..SheetObj.TableName.."` (\n")
-- 插入表尾(包括建立列,設置主鍵(默認第一列就是主鍵),引擎類型,編碼方式)
WriteOutFile:write(tCreateSql.." PRIMARY KEY (`"..SheetObj.ColList[1].ColName.."`)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8;\n\n")
-- 循環插入數據的過程
--WriteOutFile:write("insert into `"..SheetObj.TableName.."`(`"..table.concat(tNameList, "','").."`) values ("..table.concat (RowDataList, ", ")..";\n")
for i, col in ipairs(RowDataList) do
WriteOutFile:write("INSERT INTO `"..SheetObj.TableName.."` VALUES ("..table.concat(col, ", ")..");\n")
end
print("INFO_4: Table: ".. SheetObj.TableName.." create success ...")
return 1
end
-- 打開excel表
-- 參數tExl:爲excel讀寫句柄;file:爲完整的文件路徑及文件名;filename爲生成的文件名
function exl2sql.OpenExcel(tExl, file, filename)
-- 打印起始信息
print("INFO:file: "..file.." to "..filename.." start...")
if tExl == nil then print("ERROR_5: need lua library!") return end
-- 加載目標文件
local tBook=tExl.Workbooks:Open(file)
if tBook == nil then print("ERROR_6: Excel file: "..file.." open fail!") tExl.Application:quit() tExl=nil return end
-- 獲取excel中所有有效的sheet信息
local sheetlist = exl2sql.GetSheetInfo(tExl, tBook)
if sheetlist == nil then tBook:close() tExl.Application:quit() tExl=nil return end
-- 打開目標sql文件
os.remove(filename) -- 先刪除一遍
local WriteOutFile = io.open(filename, "a")
if WriteOutFile == nil then print("ERROR_7: Create sql file: "..filename.." fail!") tBook:close() tExl.Application:quit() tExl=nil return end
-- 插入文件編碼方式
-- WriteOutFile:write("set names \"utf8\";\n")
WriteOutFile:write("\nSET FOREIGN_KEY_CHECKS=0;\n")
-- 向sql文件中寫入數據
for i, v in ipairs(sheetlist)do
local res = exl2sql.CreateSql(tExl, tBook, v, WriteOutFile)
-- 如果數據寫入失敗,就刪除sql文件
if res == nil then
WriteOutFile:close()
print("ERROR_8: Sheet write fail !")
os.remove(filename)
-- 關閉excel文件
tBook:close()
return
end
end
-- 關閉sql文件
WriteOutFile:close()
-- 關閉excel文件
tBook:close()
tExl.Application:quit()
tExl=nil
-- 打印
print("INFO:file: "..file.." to "..filename.." end...success!")
return
end
--程序入口
function exl2sql.MainStart()
-- 創建讀取文件類型
local tExl=luacom.CreateObject("Excel.Application")
-- 獲取當前目錄下的所有excel文件
local AllFile, AllFileName = exl2sql.GetAllXlsxFile(lfs.currentdir());
for i,ofile in ipairs(AllFile) do
-- 獲取單個文件的所有table屬性
local exlAllTable = exl2sql.OpenExcel(tExl, ofile, AllFileName[i])
--if exlAllTable == nil then return end
print("\n\n\n")
end
-- 關閉句柄
tExl.Application:quit()
tExl=nil
end
exl2sql.MainStart()