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算法之栈(stack)的实现
Aug 18 Python
Python中为feedparser设置超时时间避免堵塞
Sep 28 Python
Python获取服务器信息的最简单实现方法
Mar 05 Python
编写Python脚本批量下载DesktopNexus壁纸的教程
May 06 Python
python 爬取微信文章
Jan 30 Python
Python基础中所出现的异常报错总结
Nov 19 Python
Python实现的中国剩余定理算法示例
Aug 05 Python
获取python文件扩展名和文件名方法
Feb 02 Python
numpy添加新的维度:newaxis的方法
Aug 02 Python
浅谈Python3识别判断图片主要颜色并和颜色库进行对比的方法
Oct 25 Python
解决TensorFlow模型恢复报错的问题
Feb 06 Python
python3.7 openpyxl 在excel单元格中写入数据实例
Sep 01 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
memcache一致性hash的php实现方法
2015/03/05 PHP
php结合正则批量抓取网页中邮箱地址
2015/05/19 PHP
thinkPHP简单调用函数与类库的方法
2017/03/15 PHP
基于Web标准的UI组件 — 树状菜单(2)
2006/09/18 Javascript
参考:关于Javascript中实现暂停的几篇文章
2007/03/04 Javascript
解决html按钮切换绑定不同函数后点击时执行多次函数问题
2014/05/14 Javascript
Javascript核心读书有感之表达式和运算符
2015/02/11 Javascript
使用ionic在首页新闻中应用到的跑马灯效果的实现方法
2017/02/13 Javascript
vue.js事件处理器是什么
2017/03/20 Javascript
教你5分钟学会用requirejs(必看篇)
2017/07/25 Javascript
使用异步组件优化Vue应用程序的性能
2019/04/28 Javascript
jquery实现选项卡切换代码实例
2019/05/14 jQuery
Vue中的组件及路由使用实例代码详解
2019/05/22 Javascript
vue axios post发送复杂对象问题
2019/06/04 Javascript
IDEA安装vue插件图文详解
2019/09/26 Javascript
Vue实现PC端靠边悬浮球的代码
2020/05/09 Javascript
基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析
2020/12/30 Vue.js
Python中的两个内置模块介绍
2015/04/05 Python
解决Pycharm中import时无法识别自己写的程序方法
2018/05/18 Python
使用python实现回文数的四种方法小结
2019/11/24 Python
浅析python 动态库m.so.1.0错误问题
2020/05/09 Python
浅谈pandas dataframe对除数是零的处理
2020/07/20 Python
用HTML5 实现橡皮擦的涂抹效果的教程
2015/05/11 HTML / CSS
美国最大的高尔夫发球时间预订网站:TeeOff.com
2018/03/28 全球购物
英国顶级珠宝品牌之家:John Greed
2018/06/09 全球购物
国家地理在线商店:Shop National Geographic
2018/06/30 全球购物
师范毕业生个人求职信
2013/12/09 职场文书
银行类自荐信
2014/02/04 职场文书
平安建设实施方案
2014/03/19 职场文书
2014年教师业务学习材料
2014/05/12 职场文书
环保倡议书400字
2014/05/15 职场文书
医药公司采购员岗位职责
2015/04/03 职场文书
2015年市场营销工作总结
2015/07/23 职场文书
Nginx反向代理配置的全过程记录
2021/06/22 Servers
为什么MySQL 删除表数据 磁盘空间还一直被占用
2021/10/16 MySQL
mysql通过group by分组取最大时间对应数据的两种有效方法
2022/09/23 MySQL