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中使用语句导入模块或包的机制研究
Mar 30 Python
python在控制台输出进度条的方法
Jun 20 Python
Python实现字典(dict)的迭代操作示例
Jun 05 Python
Python2和Python3中urllib库中urlencode的使用注意事项
Nov 26 Python
Python除法之传统除法、Floor除法及真除法实例详解
May 23 Python
python识别图像并提取文字的实现方法
Jun 28 Python
django迁移数据库错误问题解决
Jul 29 Python
使用selenium和pyquery爬取京东商品列表过程解析
Aug 15 Python
python用requests实现http请求代码实例
Oct 31 Python
django admin 添加自定义链接方式
Mar 11 Python
django ORM之values和annotate使用详解
May 19 Python
Python编解码问题及文本文件处理方法详解
Jun 20 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 向右侧拉菜单实现代码,测试使用中
2009/11/03 PHP
解析php通过cookies获取远程网页的指定代码
2013/06/25 PHP
PHP JSON出错:Cannot use object of type stdClass as array解决方法
2014/08/16 PHP
详解PHP数组赋值方法
2015/11/07 PHP
脚本吧 - 幻宇工作室用到js,超强推荐share.js
2006/12/23 Javascript
javascript题目,重写函数让其无限相加
2012/02/15 Javascript
获得Javascript对象属性个数的示例代码
2013/11/21 Javascript
原生JS操作网页给p元素添加onclick事件及表格隔行变色
2013/12/01 Javascript
js处理表格对table进行修饰
2014/05/26 Javascript
JS+CSS实现的日本门户网站经典选项卡导航效果
2015/09/27 Javascript
jQuery自定义数值抽奖活动代码
2016/06/11 Javascript
js实现StringBuffer的简单实例
2016/09/02 Javascript
简单学习vue指令directive
2016/11/03 Javascript
基于JS实现限时抢购倒计时间表代码
2017/05/09 Javascript
jQuery each和js forEach用法比较
2019/02/27 jQuery
[01:20]DOTA2 齐天大圣至宝动态展示
2016/12/13 DOTA
[57:31]DOTA2-DPC中国联赛 正赛 SAG vs CDEC BO3 第一场 2月1日
2021/03/11 DOTA
使用Python的内建模块collections的教程
2015/04/28 Python
python解决汉字编码问题:Unicode Decode Error
2017/01/19 Python
Python实现的简单读写csv文件操作示例
2018/07/12 Python
解决Django中调用keras的模型出现的问题
2019/08/07 Python
python字符串替换re.sub()实例解析
2020/02/09 Python
Python使用pyyaml模块处理yaml数据
2020/04/14 Python
python脚本第一行如何写
2020/08/30 Python
Python Sqlalchemy如何实现select for update
2020/10/12 Python
Python classmethod装饰器原理及用法解析
2020/10/17 Python
HTML5 Canvas 实现K线图的示例代码
2019/12/23 HTML / CSS
数据库的约束含义
2012/09/09 面试题
AURALog面试题软件测试方面
2013/10/22 面试题
分层教学实施方案
2014/03/19 职场文书
捐款倡议书格式范文
2014/05/14 职场文书
数据保密承诺书
2014/06/03 职场文书
2014年居委会工作总结
2014/12/09 职场文书
幼儿园中班教育随笔
2015/08/14 职场文书
高中团支书竞选稿
2015/11/21 职场文书
MySQL和Oracle批量插入SQL的通用写法示例
2021/11/17 MySQL