python脚本查询远程mysql数据库后把结果更新到本地数据库

本文介绍了一种使用Python脚本进行数据库增量备份的方法,通过对比本地和生产数据库的ID,实现数据的高效同步。

写在文前:本文中的代码经过翻阅相关库的文档和阅读CSDN中前辈的代码整理而成,在此先感谢这些前辈们的文章,由于打的太杂太多,无法一一告知,敬请原谅。
由于公司业务的需求,需要把生产数据库的一个表定时备份到本地的数据库相应的表上,由于在生产数据库上的账号只有只读权限,使用Navicat做定时任务的话效率低资源占用高并且不稳定,所以写 了 一个python脚本来做增量备份。
1、全量备份数据表
2、获取本地数据表的最大ID
3、查询生产表>本地表最大ID的数据
4、获取生产表查询结果
5、把4的查询结果导入本地数据库

脚本需要用到pymysq、pandas、sqlalchemy、os、datetime这三个库,如果没有的话需要先安装。安装使用PIP方式:

pip install 库名   

查询已安装的库:

pip list

以下是脚本的代码部份:

# 导入相关的代码块
import pymysql
import pandas as pd
import os
from datetime import datetime
from sqlalchemy import create_engine
from sqlalchemy.types import NVARCHAR, Float, Integer
start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 获取开始时间 格式为年-月-日 时:分:秒
os.getcwd() # 返回当前进程的工作目录,如果要导出导入本地文件时要用到。

# 使用connect连接数据库
# 连接本地数据库
db1 = pymysql.connect("localhost",   # 本地数据库地址
                     "root",		# 数据库账号
                     "password",	# 密码
                     "data",	# 数据库名字
                     charset="utf8" #字符编码)
# 获取游标并执行
cursor = db1.cursor(pymysql.cursors.DictCursor)
cursot = db1.cursor()

查询本地表中最后的一条数据,由于这张表的ID是自动增长列,所以新增行的ID肯定比当前ID大。我们先查询出本地表的最后一个ID

# SQL查询语句查询最后行的ID
eng1 = '''SELECT
        table.id AS `最新条目`
        FROM
        table
        ORDER BY table.id DESC LIMIT 1 '''
# 执行SQL语句
try:
    cursor.execute(eng1)
    df = cursor.fetchone() 
    df = ('%(最新条目)d' % df) # 由于查询结果是字典,所以在这里需要转换一下,只需要获取它的值并转换成int重新定义
    print(df)             # 查看转换后的效果,方便调试用,实际运行时可以注释掉

except:
    print('查询错误:变量df没有定义!')     # try执行错误提示
db1.close()  # 断开db1数据库连接

到这一步已经定位到了本地表的最后一条数据。接下来要做的是查询并获得生产表的新增的行。

#同样的方法,先连接生产表数据库
db2 = pymysql.connect("localhost",   # 生产数据库地址
                     "root",		# 生产数据库账号
                     "password",	# 生产数据库密码
                     "data",	# 生产数据库名字
                     charset="utf8" #字符编码)
# 获取游标并执行
cursor = db2.cursor(pymysql.cursors.DictCursor)
cursot = db2.cursor()
# 查询生产表的对比本地表的新数据
eng2 = '''SELECT * FROM table WHERE table.id > %s ''' % df  #查询比本地表新的数据
try:
    cursor.execute(eng2)
    df2 = cursor.fetchall()
    row = cursor.rowcount    # 返回执行结果影响的行数
#    print(df2)
# 导出为CSV文件
    print('导出中……')   # 调试用,正式运行时可不要
    inp = pd.DataFrame(df2)  # 查询结果是字典,由于我们要使用pd.to_sql,所以要先转为DataFrame
    
    inp.to_csv('data.csv', sep=',',index=False) # 导到本地CSV文件,如果更新数据量大时可用,
												 # 再使用时需用pd.to_csv()导入
#    print(inp)  # 打印查询结果,调试用
    print('导出完成!')   # 调试用。
except:
    print('错误:变量inp没有被定义!')
print(inp)
db2.close() # 关闭db2连接,注意每次使用connect连接完成后需要断开

这一步完成后,已经获得了完整的新数据,可以在运行目录中打开data.csv文件查看结果(注,可以不导出CSV文件,只保留DataFrame转换即可)。
接下来开始进行把数据导入本地mysql中。注意pd.to_sql()不能使用pymysql.connect连接,所以我们用sqlalchemy进行连接数据库

# 建立本地数据库连接
engine = create_engine('mysql+pymysql://root:password@localhost:3306/data')
con = engine.connect()
# 自定义函数:pandas类型和sql类型转换
def map_types(inp):
    dtypedict = {}
    for i, j in zip(inp.columns, inp.dtypes):
        if "object" in str(j):
            dtypedict.update({i: NVARCHAR(length=255)})
        if "float" in str(j):
            dtypedict.update({i: Float(precision=2, asdecimal=True)})
        if "int" in str(j):
            dtypedict.update({i: Integer()})
    return dtypedict
# 自定义函数赋值变量
 dtypedict = map_types(inp)
# 将数据导入mysql
inp.to_sql(name='table', con=con, if_exists='append', index=False, dtype=dtypedict)

stop_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 获取结束时间
print('从%s开始-%s结束,本次共备份%s条数据' % (start_time,stop_time,row))  # 打印执行结果,调试用。
# 用TXT记录运行日志
txt = open('log.txt','a') # 以增加写入的方式打开txt文件
txt.write(''%s开始-%s结束,本次共备份%s条数据 \n' % (start_time,stop_time,row)')
txt.close()

pd.to_sql()参数:name=‘表名’,con=连接方式,if_exists= append:追加 /replace:删除原表,建立新表再添加 /fail:什么都不干。dtype = 数据类型,这里使用的是自定义函数中转换的数据类型。
补充一下:使用SQLAlchemy连接数据库时可能会提示缺少MYSQLdb而出错,由于python3已经不再兼容MYSQLdb了,当提示需要安装MYSQLdb时,我们要安装mysqlclient这个库,同样使用pip install安装即可。
本人还是处于学习PYTHON的阶段,如有错误,敬请指正,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值