之前有群友反應同auzmdttm事給了他乙個幾百mb的sql指令碼,匯入資料庫再從資料庫讀取資料有點慢,想了解下有沒有可以直接讀取sql指令碼到pandas的方法。
我考慮了一下sql指令碼也就只是乙個文字檔案而已,而且只有幾百mb,現代的機器足以把它一次性全部載入到記憶體中,使用python來處理也不會太慢。
我簡單研究了一下sql指令碼的匯出格式,並根據格式寫出了以下sql指令碼的讀取方法。
注意:該讀取方法只針對sqlyog匯出的mysql指令碼測試,其他資料庫可能**需要根據實際情況微調。
讀取方法:
from io import stringio
impo程式設計客棧rt pandas as pd
import re
def read_sql_script_all(sql_file_path, quotechar="'") -> (str, dict):
insert_check = re.compile(r"insert +into +`?(\w+?)`?\(", re.i | re.a)
with open(sql_file_path, encoding="utf-8") as f:
sql_txt = f.read()
end_pos = -1
df_dict = {}
while true:
match_obj = insert_check.search(sql_txt, end_pos+1)
if not match_obj:
break
table_name = match_obj.group(1)
start_pos = match_obj.span()[1]+1
end_pos = sql_txt.find(";", start_pos)
tmp = re.sub(r"\)( values |,)\(", "\n", sql_txt[start_pos:end_pos])
tmp = re.sub(r"[`()]", "", tmp)
df = pd.read_csv(stringio(tmp), quotechar=quotechar)
dfs = df_dict.setdefault(table_name, )
dfs.append(df)
for table_name, dfs in df_dict.items():
df_dict[table_name] = pd.concat(dfs)
return df_dict
引數:
返回:乙個字典,鍵程式設計客棧是表名,值是該錶對應的資料所組成的datafream物件
下面我測試讀取下面這個sql指令碼:
其中的表名是index_test:
df_dict = read_sql_script_all("d:/tmp/test.sql")
df = df_dict['index_test']
df.head(10)
結果:可以看到能順利的直接從sql指令碼中讀取資料生成datafream。
當然上面寫的方法是一次性讀取整個sql指令碼的所有表,結果為乙個字典(鍵為表名,值為datafream)。但大部分時候我們只需要讀取sql指令碼的某一張表,我們可以改造一下上面的方法:
def read_sql_script_by_tablename(sql_file_path, table_name, quotech"'") -> (str, dict):
insert_check = re.compile(r"insert +into +`?(\w+?)`?\(", re.i | re.a)
with open(sql_file_path, encoding="utf-8") as f:
sql_txt = f.read()
end_pos = -1
dfs =
while true:
match_obj = insert_check.search(sql_txt, end_pos+1)
if not match_obj:
break
start_pos = match_obj.span()[1]+1
end_pos = sql_txt.find(";", start_pos)
if table_name != match_obj.group(1):
continue
tmp = re.sub(r"\)( values |,)\(", "\n", sql_txt[start_pos:end_pos])
tmp = re.sub(r"[`()]", "", tmp)
df = pd.read_csv(stringio(tmp), quotechar=quotechar)
dfs.append(df)
return pd.concat(dfs)
引數:
返回:讀取**:
df = read_sql_script_by_tablename("d:/tmp/test.sql", "index_test")
df.head()
結果:在寫完上面的方法後,我又想到另一種解決思路,就是將sql指令碼轉換成sqlite語法的sql語句,然後直接載入。各種型別的資料庫的sql語句變化較大,下面的方法僅針對sqlyog匯出的mysql指令碼測試通過,如果是其他的資料庫,可能下面的方法仍然需要微調。最好是先自行將sql指令碼轉換為sqlite語法的sql語句後,再使用我寫的方法載入。
載入sql指令碼的方法:
from sqlalchemy import create_ewww.cppcns.comngine
import pandas as pd
import re
def load_sql2sqlite_conn(sqltxt_path):
create_rule = re.compile("create +table [^;]+;", re.i)
insert_rule = re.compile("insert +into [^;]+;", re.i)
with open(sqltxt_path, encoding="utf-8") as f:
sqltxt = f.read()
engine = create_engine('sqlite:///:memory:')
pos = -1
while true:
match_obj = create_rule.search(sqltxt, pos+1)
if match_obj:
pos = match_obj.span()[1]
sql = match_obj.group(0).replace("auto_increment", "")
sql = re.sub("\).+;", ");", sql)
engine.execute(sql)
match_obj = insert_rule.search(sqltxt, pos+1)
if match_obj:
pos = match_obj.span()[1]
sql = match_obj.group(0)
engine.execute(sql)
else:
break
tablenames = [t[0] for t in engine.execute(
"select tbl_name from sqlite_master where type='table';").fetchall()]
return tablenames, engine.connect()
引數:sql_file_path:sql指令碼的位置
返回:兩個元素的元組,第乙個元素是表名列表,第二個元素是sqlite記憶體虛擬連線
測試讀取:
tablenames, conn = load_sql2sqlite_conn("d:/tmp/test.sql")
tablename = tablenames[0]
print(tablename)
df = pd.read_sql(f"select * from ;", conn)
df結果:
mysql直接匯入sql指令碼文件
我的使用者名稱是root 密碼是123 sql指令碼存在d盤根目錄下 名字為test.sql 資料庫為名為 db nevermore 有兩種方法可以執行指令碼 1 開啟cmd輸入以下命令 不需要轉換目錄 mysql u root p123 進入mysql後 mysql use db nevermor...
pandas檔案讀取
改變工作路徑 import os print os.getcwd 列印當前工作目錄 print os.listdir os.chdir c users administrator import pandas as pd for price in dfs1 print price 讀取資料是指定乙個列...
pandas讀取資料
導庫 import pandas as pd fpath d 123.csv 讀取資料 book pd.read csv fpath 檢視全部內容 book idusename course01 張三7512 李四8023 王二8334 張華9045 小明7856 小紅7667 小七90 檢視前5行...