1. 程式人生 > >分享一個自己寫的用python比對資料庫表資料的指令碼

分享一個自己寫的用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中的一個結果:




相關推薦

分享一個自己python資料庫資料指令碼

最近在做一個數據庫異構複製的專案,客戶表示需要一個數據比對的工具,我就自己寫了一個異構資料庫的比對python指令碼.這個比對指令碼只能比對數量,不能比對具體的記錄.使用的sql語句也是最基礎的select count(*) 這種,沒有開併發所以對大表可能比對時間稍長. 基

分享一個自己的MVC EF 增刪改查 無重新整理分頁程式

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

分享一個Python遠端命令和檔案(夾)傳輸類

最近在跟一個自動化釋出平臺的建設事項,其中 Linux 系統的遠端控制通道則由我獨立開發完成,其中涉及到了 Linux 系統遠端命令和檔案傳輸操作。 因為之前寫 Linux 系統密碼管理系統的時候,用的是 Paramiko 的 SSHClient。所以,我這次依然採用 Paramiko 來做實現,程式碼雖短

週末閒著無聊分享一個自己的帶呼吸效果的android水波紋自定義view

無圖無真相,廢話不多說先來看看最終效果: 用法: 1.匯入自定義屬性檔案(將這個檔案放在 res/values 下) attrs.xml <span style="font-size:18px;"><?xml version="1.0" encodi

分享一個自己的WPF換膚窗體WPF.DazzleUI

最近自己在自學WPF,看了網上很多前輩的WPF例子,覺得很炫,自己也有點衝動,就嘗試著寫了一下。 桌面程式嘛,要炫起來,當然首先得窗體先炫起來,所以就自己寫了一個可以換膚的WPF窗體基類。 不多說,先上圖: 怎麼樣,看起來效果還是不錯吧。 先發個demo的下載地址: 例

分享一個自己的vue多語言插件smart-vue-i18n

https 實現 template contain 解析 前言 了解 pre prot 前言 目前有比較成熟的方案(vue-i18n)了解了下,並且實用了一下感覺對於我在使用的項目來說略顯臃腫,功能比較多,所以壓縮的會比較大,在移動端不太適合所以自己花一天時間擼了一個vu

分享一個自己的取中國農歷相關數據的類。包含:農歷年月日,生肖,星座,年齡,天幹,地支等方法

png chinese 1.2 ins Oday 當前 for alt tdi 分享一個自己寫的取中國農歷相關數據的類。包含:農歷年月日,生肖,星座,年齡,天幹,地支等方法。此類自己花了一上午的時間寫的,適用於像相親網等類似的網站 主要使用了微軟針對東亞地區的農歷類Chi

php 如何在HTML頁面中實現資料庫資料的增刪改查

  上一篇詳細說明了如何將資料庫中的資料列印到html頁面上,本篇將介紹如何在HTML頁面的表格裡進行對資料庫內容的增刪改查還是借用上一篇的頁面,在此基礎上增加了操作按鈕:<!doctype html><html><head><meta charset="utf-8"

自己的low端口掃描 的socket

簡單端口掃描nmap os sys socket main(): portlist=[,,,,] ip_mode1=ip_mode2=ip_mode3=range_=Banner=print(Banner.upper()) print(.upper(),end=) i port

windows上快速調自己python小程序

python 密碼箱 工具制作 windows平臺上快速調用python程序 場景1:某雲平臺的賬號/或密碼比較長,一旦瀏覽器緩存失效,就要去郵件/文件查找,費時費力 場景2:由於某些場景,強制每N天更換密碼。簡單密碼箱,密碼保存,自動copy到粘貼板 場景3:python功能強大,寫了個小程序,

分享一個簡單易python並行模組【PP模組】

目前個人計算機大都是多核的,但是在執行python程式的時候會發現實際上只有一個核心(CPU)在跑程式碼,另外幾個核心都在偷懶呢,如下圖  平行計算的目的是將所有的核心都執行起來以提高程式碼的執行速度,在python中由於存在全域性直譯器鎖(GIL)如果使用預設的python多執行緒進行平行計算可能會發現程

沒時間看。先記下。跟之前已經好程序下。

變量 正在 all tor pro str state 程序 settings using System; using System.Drawing; using System.Collections; using System.ComponentModel; u

分享一個PHP調RestFul接口的函數

new highlight ray 參數 true post string 分享 tran /** * [http 調用接口函數] * @Date 2016-07-11 * @Author GeorgeHao * @param string $u

【轉】python對數據庫數據的腳本

%s import gpa post parse pwd 基本原理 -- get 最近在做一個數據庫異構復制的項目,客戶表示需要一個數據比對的工具,我就自己寫了一個異構數據庫的比對python腳本.這個比對腳本只能比對數量,不能比對具體的記錄.使用的sql語句也是最基礎的s

一個自己的MVC框架

xml文件 ast target 實現類 讀取 能說 位置 加載 -i   也有個一周沒有更新博客了,其實我沒有偷懶,因為之前一直在看Spring源碼,所以想著去寫一個類Spring的框架,也沒有給自己定什麽高的要求,簡單實現MVC、AOP、IOC等功能就行。現在這個框架基

elastic 部分更新 retry_on_conflict 和 數據庫鎖 詳細

and last conf 區分 文檔 刪除 階段 不同 重建 1 數據庫的 update 在修改這條數據的的過程中(這個過程指的是 數據庫執行update 到 事務提交的過程中 )為這條數據加上 寫鎖,阻止 別的事務 對鎖定數據的修改,請求後一個修改事務的線程阻塞,直到

Python語言任意影象進行m*n的均勻分塊(思路非常清晰,步驟簡單)

目錄 1.讀取原始影象 2.網格劃分,將影象劃分為m*n塊 2.1分塊後圖像的儲存問題 2.2影象的裁剪 2.3影象長寬的整除問題 方法一:四捨五入法

一個自己的字串匹配函式...

v3.0  1層迴圈 function match(x,y){ for(var j=0,i=0;j<y.length;j++) { if(x[i]==y[j]) i++; if(i==x.length) retu

windows7搭建FTP伺服器並且python實現FTP伺服器的一系列

0x00:windows7搭建FTP伺服器 前言:windows7搭建FTP伺服器,必須是專業版以上的windows7才可以。(不要問我為什麼,我也不知道,我找了很多Key才換成旗艦版) 點箭頭指向的地方,就能把windows7家庭普通版換成專業版甚至旗艦版了

一個自己的抓包軟體,支援外掛化指令碼分析

市場上的抓包工具已經足夠多,輕量級的,重量級的都有,典型的wireshark,smartsniff等, 各有優缺點,PowerSniff是為程式設計師準備的一款抓包工具,目標是使協議解析外掛編寫更簡單。檔案格式完全相容wiareshark和tcpdump。 原理:捕獲到資料就呼叫預設定的指令碼,將資料的指