Pandas直接讀取sql指令碼的方法

2022-09-29 13:24:12 字數 4011 閱讀 9727

之前有群友反應同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行...