Pandas直接读取sql脚本的方法


Posted in Python onJanuary 21, 2021

之前有群友反应同事给了他一个几百MB的sql脚本,导入数据库再从数据库读取数据有点慢,想了解下有没有可以直接读取sql脚本到pandas的方法。

解析sql脚本文本文件替换成csv格式并加载

我考虑了一下sql脚本也就只是一个文本文件而已,而且只有几百MB,现代的机器足以把它一次性全部加载到内存中,使用python来处理也不会太慢。

我简单研究了一下sql脚本的导出格式,并根据格式写出了以下sql脚本的读取方法。

注意:该读取方法只针对SQLyog导出的mysql脚本测试,其他数据库可能代码需要根据实际情况微调。

读取方法:

from io import StringIO
import 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

参数:

  • sql_file_path:sql脚本的位置
  • quotechar:脚本中字符串是单引号还是双引号,默认使用单引号解析

返回:

一个字典,键是表名,值是该表对应的数据所组成的datafream对象

下面我测试读取下面这个sql脚本:

Pandas直接读取sql脚本的方法

其中的表名是index_test

df_dict = read_sql_script_all("D:/tmp/test.sql")
df = df_dict['index_test']
df.head(10)

结果:

Pandas直接读取sql脚本的方法

可以看到能顺利的直接从sql脚本中读取数据生成datafream。

当然上面写的方法是一次性读取整个sql脚本的所有表,结果为一个字典(键为表名,值为datafream)。但大部分时候我们只需要读取sql脚本的某一张表,我们可以改造一下上面的方法:

def read_sql_script_by_tablename(sql_file_path, table_name, 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
  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)

参数:

  • sql_file_path:sql脚本的位置
  • table_name:被读取的表名
  • quotechar:脚本中字符串是单引号还是双引号,默认使用单引号解析

返回:

该表所对应的datafream对象

读取代码:

df = read_sql_script_by_tablename("D:/tmp/test.sql", "index_test")
df.head()

结果:

Pandas直接读取sql脚本的方法

将sql脚本转换为sqlite格式并通过本地sql连接读取

在写完上面的方法后,我又想到另一种解决思路,就是将sql脚本转换成sqlite语法的sql语句,然后直接加载。各种类型的数据库的sql语句变化较大,下面的方法仅针对SQLyog导出的mysql脚本测试通过,如果是其他的数据库,可能下面的方法仍然需要微调。最好是先自行将sql脚本转换为sqlite语法的sql语句后,再使用我写的方法加载。

加载sql脚本的方法:

from sqlalchemy import create_engine
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 {tablename};", conn)
df

结果:

Pandas直接读取sql脚本的方法

到此这篇关于Pandas直接读取sql脚本的文章就介绍到这了,更多相关Pandas读取sql脚本内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python解析xml文件实例分享
Dec 04 Python
状态机的概念和在Python下使用状态机的教程
Apr 11 Python
深入理解Python中各种方法的运作原理
Jun 15 Python
Python中如何优雅的合并两个字典(dict)方法示例
Aug 09 Python
python实现五子棋游戏
Jun 18 Python
anaconda如何查看并管理python环境
Jul 05 Python
用python给自己做一款小说阅读器过程详解
Jul 11 Python
python求平均数、方差、中位数的例子
Aug 22 Python
python安装scipy的步骤解析
Sep 28 Python
python列表切片和嵌套列表取值操作详解
Feb 27 Python
Python如何使用vars返回对象的属性列表
Oct 17 Python
python判断all函数输出结果是否为true的方法
Dec 03 Python
python asyncio 协程库的使用
Jan 21 #Python
python palywright库基本使用
Jan 21 #Python
python Scrapy爬虫框架的使用
Jan 21 #Python
python 可视化库PyG2Plot的使用
Jan 21 #Python
详解基于Facecognition+Opencv快速搭建人脸识别及跟踪应用
Jan 21 #Python
Python实现石头剪刀布游戏
Jan 20 #Python
python程序实现BTC(比特币)挖矿的完整代码
Jan 20 #Python
You might like
php 无极分类(递归)实现代码
2010/01/05 PHP
PHP中4个加速、缓存扩展的区别和选用建议
2014/03/12 PHP
php图片处理函数获取类型及扩展名实例
2014/11/19 PHP
windows下配置php5.5开发环境及开发扩展
2014/12/25 PHP
php array_walk_recursive 使用自定的函数处理数组中的每一个元素
2016/11/16 PHP
关于php支持的协议与封装协议总结(推荐)
2017/11/17 PHP
php的无刷新操作实现方法分析
2020/02/28 PHP
JQuery实现倒计时按钮具体方法
2013/11/14 Javascript
javascript动态修改Li节点值的方法
2015/01/20 Javascript
jQuery+PHP实现动态数字展示特效
2015/03/14 Javascript
jQuery中通过ajax调用webservice传递数组参数的问题实例详解
2016/05/20 Javascript
JavaScript中数据类型转换总结
2016/12/25 Javascript
canvas绘制一个常用的emoji表情
2017/03/30 Javascript
详解Angular系列之变化检测(Change Detection)
2018/02/26 Javascript
vue如何进行动画的封装
2018/09/26 Javascript
js中数组对象去重的两种方法
2019/01/18 Javascript
Vuex的actions属性的具体使用
2019/04/14 Javascript
详解element-ui中el-select的默认选择项问题
2019/08/02 Javascript
vue 动态表单开发方法案例详解
2019/12/02 Javascript
Element Popover 弹出框的使用示例
2020/07/26 Javascript
jQuery冲突问题解决方法
2021/01/19 jQuery
python的类方法和静态方法
2014/12/13 Python
Python使用PyCrypto实现AES加密功能示例
2017/05/22 Python
python基础之包的导入和__init__.py的介绍
2018/01/08 Python
Python常用数据类型之间的转换总结
2019/09/06 Python
深入分析python 排序
2020/08/24 Python
Python制作一个仿QQ办公版的图形登录界面
2020/09/22 Python
Jar包的作用是什么
2014/03/30 面试题
建筑工地门卫岗位职责
2014/04/30 职场文书
市场营销工作计划书
2014/05/06 职场文书
我读书我快乐演讲稿
2014/05/07 职场文书
马丁路德金演讲稿
2014/05/19 职场文书
同学聚会策划方案
2014/06/06 职场文书
升学宴学生答谢词
2015/01/05 职场文书
工作证明书
2015/06/15 职场文书
2016元旦文艺汇演主持词
2015/07/06 职场文书