【转】用python比对数据库表数据的脚本
最近在做一个数据库异构复制的项目,客户表示需要一个数据比对的工具,我就自己写了一个异构数据库的比对python脚本.这个比对脚本只能比对数量,不能比对具体的记录.使用的sql语句也是最基础的select count(*) 这种,没有开并发所以对大表可能比对时间稍长.
基本原理是将需要比对的数据写到一张表里,先读取那个表里的数据,取出需要比对的表.然后创建多进程,同时在原端和目标端count.然后将count的结果写到一个excel文件中.
其中最关键的就是那张表.只要将那张表里的数据搞对了,基本就不会有什么问题.
目前支持的数据库有oracle,mysql,postgresql,sqlserver.程序分为三个部分
1.数据库配置文件
首先需要在python代码的相同目录下写一个名为check.ini的配置文件.下面一个配置文件例子:
[DATA]
#配置原端数据库,下面的ORACLE需要与后面的项匹配
source=ORACLE
#配置目标端数据库,下面的POSTGRESQL需要与后面的项匹配
target=POSTGRESQL
#配置比对表的数据库,需要与下面的配置项匹配
check_node=ORACLE
#配置比对表数据库的用户,如果是oracle是用户,如果是mysql,pg,mssql则是数据库名
check_owner=suq
#配置比对表的表名,区分大小写
check_table=check_table #配置mysql的连接串.注意MYSQL必须大写而且必须是以MYSQL开头,例如想比对多个mysql可以写MYSQL1,MYSQL2等
#下面的几个配置同样需要以相应例子开头,因为程序就是以项的开头来确认是哪种数据库的
[MYSQL]
db_host=192.168.56.25
db_port=3306
db_user=root
db_pwd=root
db_dbname=major [ORACLE]
db_host=192.168.56.30
db_port=1521
db_user=dsg
db_pwd=dsg
db_sid=bre1 [POSTGRESQL]
db_host=192.168.56.50
db_port=5432
db_user=postgres
db_pwd=postgres
db_dbname=msgdb [MSSQL]
db_host=192.168.56.101
db_port=1433
db_user=sa
db_pwd=sa
db_dbname=master
2.创建一个比对表.
例如我上面的例子放在suq用户下的check_table中
具体的表结构如下:
- SQL> desc check_table
- Name Null? Type
- ----------------------------------------- -------- ----------------------------
- SOWNER VARCHAR2(30)
- SNAME VARCHAR2(30)
- TOWNER VARCHAR2(30)
- TNAME VARCHAR2(30)
分别表示原端的用户名,表名,目标端用户名表名,如果不是用户的那么就是数据库名.
看一下表内我的测试数据:
- SQL> select * from check_table;
- SOWNER SNAME TOWNER TNAME
- ------------------------------ ------------------------------ ------------------------------ ------------------------------
- suq "t1" suq t1
- suq "t2" suq t2
- suq "t3" suq t3
- suq "t4" suq t4
这里的数据要特别注意,必须写对否则可能运行会报错.需要注意的一般原因是不同的数据库对大小写敏感不同.因此建议在写好这些数据后,手动到数据库查一下,例如
select count(*) from suq."t1"
看这样的sql对不对.
3.就是主程序
需要注意的是我连接各种数据库分别使用的如下python模块,写excel使用XlsxWriter模块:
- C:\Users\think>pip list
- cx-Oracle (5.2.1)
- MySQL-python (1.2.4)
- psycopg2 (2.6.2)
- pymssql (2.1.3)
- XlsxWriter (0.8.5)
下面是具体的python代码:
#coding:utf-8
import cx_Oracle as ora
import MySQLdb as my
import psycopg2 as post
import pymssql as ms
import ConfigParser as conf
import multiprocessing as mul
import xlsxwriter
import time def connect(cfg,db):
if db[0:5] == 'MYSQL':
db_host=cfg.get(db,'db_host')
db_port=cfg.get(db,'db_port')
db_user=cfg.get(db,'db_user')
db_pwd=cfg.get(db,'db_pwd')
db_dbname=cfg.get(db,'db_dbname')
conn = my.connect(host=db_host,port=int(db_port),user=db_user,passwd=db_pwd,db=db_dbname)
return conn
elif db[0:6] == 'ORACLE':
db_host=cfg.get(db,'db_host')
db_port=cfg.get(db,'db_port')
db_user=cfg.get(db,'db_user')
db_pwd=cfg.get(db,'db_pwd')
db_sid=cfg.get(db,'db_sid')
conn = ora.connect(db_user,db_pwd,db_host+':'+db_port+'/'+db_sid)
return conn
elif db[0:10] == 'POSTGRESQL':
db_host=cfg.get(db,'db_host')
db_port=cfg.get(db,'db_port')
db_user=cfg.get(db,'db_user')
db_pwd=cfg.get(db,'db_pwd')
db_dbname=cfg.get(db,'db_dbname')
conn = post.connect(host=db_host,port=db_port,user=db_user,password=db_pwd,database=db_dbname)
return conn
elif db[0:5] == 'MSSQL':
db_host=cfg.get(db,'db_host')
db_port=cfg.get(db,'db_port')
db_user=cfg.get(db,'db_user')
db_pwd=cfg.get(db,'db_pwd')
db_dbname=cfg.get(db,'db_dbname')
conn = ms.connect(host=db_host,port=db_port,user=db_user,password=db_pwd,database=db_dbname)
return conn def check(cfg,db,check_owner,check_table):
conn=connect(cfg,db)
cursor=conn.cursor()
sql='select * from '+check_owner+'.'+check_table
cursor.execute(sql)
table_list=[]
alldata=cursor.fetchall()
for i in alldata:
table_list.append(i)
#print table_list
return table_list def getcount(cfg,db,sql,q):
conn = connect(cfg,db)
cursor=conn.cursor()
try:
cursor.execute(sql)
countval = cursor.fetchall()[0][0]
q.put(countval)
except Exception,e:
countval="Error : "+str(e)
q.put(countval) def isdigit(num):
try:
int(num)
return True
except:
return False def comp(cfg,source,target,tablelist):
###excel start
xlsxname='check_'+str(time.strftime("%Y%m%d%H%M", time.localtime()))+'.xlsx'
workbook=xlsxwriter.Workbook(xlsxname)
top=workbook.add_format({'border':6,'align':'center','bg_color':'cccccc','font_size':13,'bold':True})
format_data_normal=workbook.add_format({'align':'center','font_size':13})
format_data_warn=workbook.add_format({'align':'center','font_size':13,'bg_color':'ff0000'})
format_data_err=workbook.add_format({'align':'center','font_size':13,'bg_color':'ffff00'})
worksheet = workbook.add_worksheet('sheet1')
worksheet.set_column('A:A',12)
worksheet.set_column('B:B',40)
worksheet.set_column('C:C',12)
worksheet.set_column('D:D',12)
worksheet.set_column('E:E',40)
worksheet.set_column('F:F',12)
worksheet.set_column('G:G',12)
title=[u'源端用户',u'源端表名',u'源端数据量',u'目标端用户',u'目标端表名',u'目标端数据量',u'差异条数']
worksheet.write_row('A1',title,top)
###excel stop
length=len(tablelist)
for i in range(length):
check_result=[]
sowner=tablelist[i][0]
sname=tablelist[i][1]
towner=tablelist[i][2]
tname=tablelist[i][3]
sql_s='select count(*) from '+sowner+'.'+sname
sql_t='select count(*) from '+towner+'.'+tname
#sql_t='select count(*) from '+towner+'.'+'\"'+tname+'\"'
q1=mul.Queue()
q2=mul.Queue()
p1=mul.Process(target = getcount,args = (cfg,source,sql_s,q1))
p2=mul.Process(target = getcount,args = (cfg,target,sql_t,q2))
p1.start()
p2.start()
count_s=q1.get()
count_t=q2.get()
p1.join
p2.join
check_result.append(sowner)
check_result.append(sname)
check_result.append(count_s)
check_result.append(towner)
check_result.append(tname)
check_result.append(count_t)
print '%s %s %s %s %s %s' %(sowner,sname,count_s,towner,tname,count_t)
#print check_result
if isdigit(count_s) and isdigit(count_t):
check_result.append(count_s-count_t)
if count_s == count_t:
worksheet.write_row('A'+str(2+i),check_result,format_data_normal)
else:
worksheet.write_row('A'+str(2+i),check_result,format_data_warn)
else:
check_result.append("Error")
worksheet.write_row('A'+str(2+i),check_result,format_data_err)
workbook.close() if __name__ == "__main__":
print "AT time {0}".format(time.ctime())
print "Begin compare ..."
cfg=conf.ConfigParser()
cfg.read('check.ini')
source=cfg.get('DATA','source')
target=cfg.get('DATA','target')
check_node=cfg.get('DATA','check_node')
check_owner=cfg.get('DATA','check_owner')
check_table=cfg.get('DATA','check_table') tablelist=check(cfg,check_node,check_owner,check_table)
comp(cfg,source,target,tablelist)
print "AT time {0}".format(time.ctime())
print "compare complete!"
raw_input("Press <ENTER>")
执行这段代码后就会读取check.ini文件,获取需要比对的原端和目标端数据库的信息,以及比对表的信息,首先将比对的表获取写到一个数组中.然后使用for循环对表进行count,再写到excel中.excel名为check_XXXX.xlsx.xxx为时间.如果在执行sql的时候报错,那么excel中以黄色标出,如果比对原端和目标端数据不一致以红色标出.
下面是我比对oracle和pg中的一个结果:
--------------
# -*- coding:utf-8 -*-
import os yesterdaynamelist=[]
todaynamelist=[]
differentnamelist=[]
areceivername=[]
test=[]
#读取 昨天生成的namelist 文件 并生成todaynamelist
namelist = open('D:\\python\\Project\\AtuoEmail\\Date\\riqi.txt','r')
linea = namelist.readlines()
# lineb = namelist.readline()
# print (namelist)
# print (linea)
# print (lineb)
# for i in linea:
# print (i)
#
for i in linea:
line=i.split()
# print(line)
yesterdaynamelist.extend(line)
# print(yestdaynamelist) # 将todaynamelist 列表输出成单列的文本。
yesterdaytxt = open("D:\\python\\Project\\AtuoEmail\\Date\\yesterdaytxt.txt","w",encoding="utf-8") #w参数 创建+复写
yesterdaytxt.close()
for i in yesterdaynamelist:
# print (i)
# print(type(i))
yesterdaytxt = open("D:\\python\\Project\\AtuoEmail\\Date\\yesterdaytxt.txt","a",encoding="utf-8")
yesterdaytxt.write(i)
yesterdaytxt.write("\n")
yesterdaytxt.close()
# todaytxt.write(todaynamelist)
# todaytxt.close() #关闭文件 # Yesterdaytxt
# temp # print (line)
# for i in line:
# print i.strip().split()[0]
# print i.strip().split()[1]
# print i.strip().split()[2] #调用 cmd生成当天最新的域控用户名单。
os.system('D:\\python\\Project\\AtuoEmail\\TodayADUser.bat') namelist = open('D:\\python\\Project\\AtuoEmail\\Date\\riqi.txt','r')
linea = namelist.readlines()
todaynamelist=[]
for i in linea:
line=i.split()
# print(line)
todaynamelist.extend(line)
# print(todaynamelist) # print(todaynamelist)
# print(yesterdaynamelist)
# print(list(set(todaynamelist).difference(set(yesterdaynamelist)))) #生成差异名单并导出文件
differentnamelist=list(set(todaynamelist).difference(set(yesterdaynamelist))) #“t”“y”对比,输出“T”中新增的元素
# print(differentnamelist)
for i in differentnamelist:
# print (i)
# print(type(i))
differentnamelist = open("D:\\python\\Project\\AtuoEmail\\Date\\differentnamelist.txt","a",encoding="utf-8")
differentnamelist.write(i)
differentnamelist.write("@dafy.com,")
differentnamelist.close()
# -*- coding:utf-8 -*-
import os yesterdaynamelist=[]
todaynamelist=[]
differentnamelist=[]
areceivername=[]
test=[]
#读取 昨天生成的namelist 文件 并生成todaynamelist
namelist = open('D:\\python\\Project\\AtuoEmail\\Date\\riqi.txt','r')
linea = namelist.readlines()
# lineb = namelist.readline()
# print (namelist)
# print (linea)
# print (lineb)
# for i in linea:
# print (i)
#
for i in linea:
line=i.split()
# print(line)
yesterdaynamelist.extend(line)
# print(yestdaynamelist) # 将todaynamelist 列表输出成单列的文本。
yesterdaytxt = open("D:\\python\\Project\\AtuoEmail\\Date\\yesterdaytxt.txt","w",encoding="utf-8") #w参数 创建+复写
yesterdaytxt.close()
for i in yesterdaynamelist:
# print (i)
# print(type(i))
yesterdaytxt = open("D:\\python\\Project\\AtuoEmail\\Date\\yesterdaytxt.txt","a",encoding="utf-8")
yesterdaytxt.write(i)
yesterdaytxt.write("\n")
yesterdaytxt.close()
# todaytxt.write(todaynamelist)
# todaytxt.close() #关闭文件 # Yesterdaytxt
# temp # print (line)
# for i in line:
# print i.strip().split()[0]
# print i.strip().split()[1]
# print i.strip().split()[2] #调用 cmd生成当天最新的域控用户名单。
os.system('D:\\python\\Project\\AtuoEmail\\TodayADUser.bat') namelist = open('D:\\python\\Project\\AtuoEmail\\Date\\riqi.txt','r')
linea = namelist.readlines()
todaynamelist=[]
for i in linea:
line=i.split()
# print(line)
todaynamelist.extend(line)
# print(todaynamelist) # print(todaynamelist)
# print(yesterdaynamelist)
# print(list(set(todaynamelist).difference(set(yesterdaynamelist)))) #生成差异名单并导出文件
differentnamelist=list(set(todaynamelist).difference(set(yesterdaynamelist))) #“t”“y”对比,输出“T”中新增的元素
# print(differentnamelist)
for i in differentnamelist:
# print (i)
# print(type(i))
differentnamelist = open("D:\\python\\Project\\AtuoEmail\\Date\\differentnamelist.txt","a",encoding="utf-8")
differentnamelist.write(i)
differentnamelist.write("@dafy.com,")
differentnamelist.close()
【转】用python比对数据库表数据的脚本的更多相关文章
- mssql sqlserver 使用sql脚本 清空所有数据库表数据的方法分享
摘要: 下文讲述清空数据库中所有表信息的方法分享,如下所示: 实验环境:sql server 2008 实现思路: 1.禁用所有约束,外键 2.禁用所有触发器 3.删除表数据 4.开启触发器 5.开启 ...
- jmeter 获取数据库表数据作为参数
jmeter - 获取数据库表数据作为参数 在jmeter中使用数据库表数据首先需要设置数据库连接,然后在创建JDBC取样器 1.创建配置元件 JDBC Connection Configuratio ...
- MSSQL 删除数据库表数据
--删除数据库表数据 慎用 create PROCEDURE sp_DeleteAllData AS ) ) ) ) ) ) begin try begin tran -- 失效索引,触发器 open ...
- (喷血分享)利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句
(喷血分享)利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句 在我们RDIFramework.NET代码生成器中,有这样一个应用,就是通过数据库表自动生成表的CREA ...
- 利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句
利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句 (喷血分享)利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句 在我们RDIFram ...
- linux下python导出sybase 数据库 表记录的方式
导出sybase 数据库 表记录的方式 1 执行启动sybase 数据库命令 code : dbeng7 gkdb 2 执行 连接sybase 数据库命令code : dbisql -c " ...
- Python向mysql数据库插入数据
一.向表tcolor中插入数据的主要流程如下: import datetimeimport pymysql.cursorsconnection = pymysql.connect(host='loca ...
- 使用python将mysql数据库的数据转换为json数据
由于产品运营部需要采用第三方个推平台,来推送消息.如果手动一个个键入字段和字段值,容易出错,且非常繁琐,需要将mysql的数据转换为json数据,直接复制即可. 本文将涉及到如何使用Python访问M ...
- SQL2008将服务器的数据库表数据插入到本地数据库
一,配置参数 exec sp_configure reconfigure exec sp_configure RECONFIGURE 若不配置参数会出现,提示这个错误: SQL Server 阻止了对 ...
随机推荐
- 启发式搜索A-Star算法 【寻找 最短路径 算法】【地理几何位置 可利用的情况】
在处理最短路径问题时,有一种启发式算法是我们应该了解的,由于其有着优秀的探索效率在各自现实项目中多有应用,它就是 A-star 算法,或 A* 算法. 个人观点: A* 算法并不保证找到的路径一 ...
- matlab学习(1)strsplit与strtok
strsplit函数用法: <1>默认使用空格符分割,返回一个cell数组 <2>也可以指定第二个参数进行分割 <3>第二个参数也可以时包含多个分隔符的元胞数组 & ...
- SEO:网站优化内容
一.内部优化 (1)meta标签优化:例如:TDK等的优化: 首页:网站名称 或者 网站名称_提供服务介绍or产品介绍 . 频道页:频道名称_网站名称. 文章 ...
- 牛客国庆集训派对Day4 J-寻找复读机
链接:https://www.nowcoder.com/acm/contest/204/J 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 1048576K,其他语言20 ...
- HDU 1907:John(尼姆博弈变形)
John Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Total Submi ...
- C语言-第一周作业
要求1: 请在你的PC或者移动设备上安装词典,该词典工具能对计算机术语进行翻译.需要在你的博客中给出安装软件的截图,请确保阅读者能从截图判断出你的被安装的设备是PC或者移动设备.(5经验值) 要求2: ...
- 回收机制GC
.NET 之 垃圾回收机制GC 一.GC的必要性 1.应用程序对资源操作,通常简单分为以下几个步骤:为对应的资源分配内存 → 初始化内存 → 使用资源 → 清理资源 → 释放内存. 2.应用程序对资源 ...
- 20165313 《Java程序设计》第三周学习总结
教材学习总结 这一章主要讲解了类的创建与使用,以及其中参数的调用方式,如何将多个对象组合,包的用法,访问权的设置和基本类封装. 1.对象注意初始化 2.包语句使用后要把对应得.java文件放到与包同名 ...
- myeclipse从svn导入文件报错:
Access restriction:The type JPEGCodec is not accessible due to restriction on required library C:\Pr ...
- Go Example--指针
package main import ( "fmt" ) func zeroval(ival int) { ival = 0 } func zeroptr(iptr *int) ...