關於使用python來實現mysql自動生成資料表
注:環境 windows 7 旗艦版 python 3.6.4 xlrd模組 pymysql模組 mysql 8.0.12 前幾天拿到一個專案需要在資料庫建立‘一堆’的表!於是就有了一個偷懶的想法! 經過努力終於完成了‘乞丐版’程式碼如下:
# -*- coding: utf-8 -*- from __future__ import unicode_literals import pymysql import xlrd #先寫一個函式,用來讀取xlsx,並生成可執行的mysql命令 def read_xlrd(s): Sfile = xlrd.open_workbook(filename=s) #讀取xlsx檔案 filename為關鍵字s是檔案路徑+名字 Sfile.sheet_names() # 獲取Excel檔案 sheet名 sheet = Sfile.sheet_by_index(0) #獲取第n頁 sheet物件 index(n) n 從0開始 #如果這裡有多頁,可以進行遍歷獲取 print(sheet.name, sheet.nrows, sheet.ncols) # 獲取當前sheet的名字 sheet行數 sheet列數 # rows = sheet.row_values(10) # 獲取當前sheet中某一整行的資料rows為一個列表 for i in range(0, sheet.nrows): # 迴圈遍歷每一行,0到該表格的最大行,for顧頭不顧尾 h = sheet.row_values(i) #獲取當前sheet 第 i 行的資料 h為一個列表 field_name, field_type, isNull, restrain = '', '', '', '' #初始化一些變數 b = 0 #通過以下判斷來拼接對應的字串 if i == 0: table_name = h[0] # 表名 l = 'create table {} ('.format(table_name) elif h[0] == '': #如果該行的資料的第0位也就是欄位名為空,則表示該行為合併過 #的單元格,無資料 b = 1 #所以跳過改行以後的判斷,並將變數b值改為1 後面會用到 pass else: field_name = h[0] + ' ' # 欄位名稱 每行的第0位為欄位名,mysql語句均以空格分隔,所以在後邊加一個空格 field_type = h[1] + ' ' # 欄位型別 每行第1位為欄位型別 if h[2] == 'N': #每行第2位,宣告該欄位是否可以為空,表中以‘N’表示不可為空 isNull = 'not null ' # 是否為空 給變數賦值 elif h[2] == '': #每行的這一位可能為空 isNull = '' #如果為空給變數賦值為空 if h[3] == '主鍵': #通過第3位判斷該欄位是否為主鍵 restrain = 'primary key' # 約束條件,給變數賦值 isNull = '' #主鍵一定不可為空,非空宣告可以取消 elif h[3] == '全表唯一性': #通過第3位判斷該欄位是否為唯一 restrain = 'unique key' #給變數賦值 elif h[3] == '': #判斷無約束條件時 restrain = '' #賦值為空 if i == sheet.nrows - 1: #判斷是否已經讀到表格的最後一行 l = l + field_name + field_type + isNull + restrain + ') character set utf8;' #拼接mysql語句尾部與分號 elif i == 0 or b == 1: #第一行和空行不需要進行拼接,直接跳過 pass else: #正常行均進行拼接每個欄位的結尾加逗號 l = l + field_name + field_type + isNull + restrain + ',' # 生成sql語句 #所有行都讀完後mysql語句拼接完成,返回給呼叫語句 return l #settings部分可以提出來拿到配置檔案中 settings = { 'host': '127.0.0.1', #為了方便測試,這裡使用本地的 'port': 3306, #連線埠 mysql 預設3306 'database': 'ajia', #要連線的資料庫名 'password': '123456', #資料庫密碼 'charset': 'utf8', #字符集 'user': 'root', #連線使用者 } conn = pymysql.connect(**settings) #連線資料庫 cur = conn.cursor() #建立遊標 cur.execute(r'use ajia;') #上邊的r'use ajia'可以替換為 'use {};'.format(settings['database']) #下面假設有13張表,我使用for迴圈來進行遍歷,具體操作時可以將這裡提取出來拿到配置檔案中,這裡要考慮檔名之間的關聯性來生成路徑 ******************** for i in range(1, 14): bt = R'/0{}.xlsx'.format(i) #檔名 s = R"D:/xlsx13" + str(bt) #檔案路徑+ l = read_xlrd(s) #呼叫函式並傳參 print(l) #列印返回值 cur.execute(l) #執行生成的mysql命令 conn.commit() cur.close() #關閉遊標 conn.close() #斷開連線
我們以下面這張表做示例: 為了方便操作,我對這張表進行了些許處理 觀察這張表可以發現,第一行是完全不用出現在mysql命令裡的!在mysql建立資料表時需要一個表名稱,所以我便將第一行的第一列換成了我們想要建立的表的名稱,這樣方便我們後續的操作!
整體思路:
1.自動建立的實質是生成mysql語句 觀察表可以得到以下: create table 表名( 欄位1 欄位型別 [是否允許為空 約束條件], 欄位1 欄位型別 [是否允許為空 約束條件] )character set utf8; 可以看到上面這段虛擬碼中,漢字部分都是需要從xslx檔案中獲取到並替換的,其餘的關鍵字及字符集都是固定不變的,當然如果需要字符集也是可以手動設定的! 2.有了第一部分的分析,我們就需要使用python的xlrd模組來獲取我們想要的資料。 3.成功獲取資料後,然後就是將拿到的資料進行判斷,根據值的不同對應不同的‘字串’,然後使用這些字串替換掉虛擬碼中的漢字,完成mysql程式碼的生成! 4.通過pymysql與mysql建立連線,然後將上邊拼接完成的字串傳給mysql進行執行,完成表的生成!
遇到的問題
1.最開始是拼接路徑的問題,最早檔案在桌面win下路徑如:C:\Users\Administrator\Desktop\筆記 '\'在python中是轉義字元,需要‘\\’,但雙斜槓後xlrd.open_workbook(filename=s)就無法讀取,嘗試加R讓直譯器不轉義,結果也不行,後來查詢可大量檔案發現可能與windows的桌面漢字路徑有關於是將檔案整個移動至D盤,加R使用反斜槓成功解決 2.第二次是字符集的問題報錯如下:SyntaxError: (unicode error) ‘utf-8’ codec can’t decode byte 0xb4 in position 2:invalid sta 最初使用sublime進行程式格式的轉化,結果很不理想,一直是gb2312,無奈之下使用notepad++將gb2312成功轉成utf8。程式成功執行。不是很清楚sublime為什麼無法完成轉碼!不過notepad++可以成功! 3.第三個問題也是坑我最深的問題,是關於mysql的最開始我的mysql是5.7版本的,可以看到上邊的例項表中有連續幾個欄位的型別都是timestamp,然後就報瞭如下錯誤:pymysql.err.InternalError: (1067, “Invalid default value for ‘updated’” 意思是預設值錯誤,查資料的結果說是mysql的嚴格模式,連續的timestamp會插入‘0000-00-00’,而mysql嚴格模式下認為該資料為非法資料!網上給出瞭解決辦法,修改配置表,於是我就去修改了結果,我的mysql炸了,由於沒有備份配置表,導致mysql服務一直無法重啟。最後不得已重灌了mysql,這次直接安裝了8.0.12版本的!也沒在報那個錯誤!至此,‘乞丐版’的自動生成表的程式完成!
多說幾句
雖然這只是‘乞丐版’但是核心已經完成,再精進無非是多些判斷,多拼接sql語句,既然可以完成表的生成那麼表記錄的插入呢?當然異曲同工!思想是一致的!這裡我就不寫了如果你有興趣可以自己去嘗試,還有讀取的也不止是xslx檔案,還有.docx 等等!有興趣的話就動手吧騷年!