2016-04-26 14 views
0

私のdbsのバックアップを取るMS-SQL dbsをバックアップするための外部ユーティリティを使用しています。 、.ldf)ファイル。復元されたMS-SQLデータベースとPythonを使用して元のDBを比較します

復元されたdbファイル(.mdf & .ldfファイル)が元のdbファイルと同じかどうか、または自動化のためにPythonを使用していないかどうかを確認する必要があります。 Pythonと統合できるdb比較を行うユーティリティはありますか?

私はこのモジュールを使用して復元のDBを比較することができれば、私は私がpymssqlに見ていた...、

答えて

0

pymssqlモジュールに探しますが、わからないのです。 pymssqlは、渡されたSQLクエリを実行して、それの出力を返します。しかし、pymssql(Windows上)のインストールは、実際には非常に難しい作業です。したがって、pymssqlを使用する代わりに、私はSQLサーバの組み込みSQLCMDユーティリティを使用してSQLクエリを実行することを推奨しました。

os.system()pythonを使用して、SQLCMDでSQLクエリを実行しました。したがって、私は自分のSQLクエリをPythonで.sqlファイルに書き込んだ後、SQLCMDに渡して出力を別のテキストファイルにリダイレクトしました。

私はまずSQLCMDを使用して、指定したデータベースのテーブルのリストを収集しました。次に、すべてのテーブルを1つずつクエリし、それらのデータを1つのテキストファイル(Original_DB_Data.txt)にドロップしました。復元されたデータベースについても、同じ手順を踏んで別のテキストファイル(Restored_DB_Data.txt)にデータをダンプしました。コードスニペットは以下の通りです: -

import os 
    def get_table_list_in_DB(Instance_name, DB_name): 

     query = 'SELECT NAME from [%s].sys.tables' %(DB_name) 
     input_file = "C:\\SQL_Data\\SQLQuery_table_list.sql" 
     output_file = "C:\\SQL_Data\\Table_list_DB-%s_Output.txt" %(DB_name) 

     with open(input_file, 'w') as f: 
      f.write(query) 

     command = 'sqlcmd -S %s -i %s -o %s' %(Instance_name, input_file, output_file) 
     os.system(command) 
     os.remove(input_file) # to delete the created .sql file 
     return output_file 


    def get_db_data(Instance_name, DB_name): 

     output_file = "C:\\SQL_Data\\DB_Data-%s_Output.txt" %(DB_name) 
     table_list = get_table_list_in_DB(Instance_name, DB_name) 

     flag = 0 
     with open(table_list, 'r') as f1, open(output_file, 'a') as f2: 
      for lines in f1: 
       if re.match("^\s", lines): 
        flag = 0 
       if flag: 
        table_data = get_table_data(Instance_name, DB_name, table_name=lines.strip()) 
        with open(table_data, 'r') as f3: 
         f2.write("##################################" + '\n') 
         f2.write('\t' +lines.strip() + '\n') 
         f2.write("##################################" + '\n') 
         f2.write(f3.read()) 
        os.remove(table_data) 
       if re.match("^----+", lines): 
        flag = 1 
     return output_file 


    def get_table_data(Instance_name, DB_name, table_name): 

     input_file = "C:\\SQL_Data\\SQLQuery_table_data.sql" 
     output_file = "C:\\SQL_Data\\Table_data_%s_Output.txt" %(table_name) 

     query = "SELECT * from [%s].dbo.[%s]" %(DB_name, table_name) 

     with open(input_file, 'w') as f: 
      f.write(query) 

     command = "sqlcmd -S %s -i %s -o %s" %(Instance_name, input_file, output_file) 
     os.system(command) 
     os.remove(input_file) 
     return output_file 

    def compare_DB_Data(DB_Detail1=[], DB_Detail2=[]): 
     get_db_data(Instance_name=DB_Detail1[0], DB_name=DB_Detail1[1]) 
     get_db_data(Instance_name=DB_Detail2[0], DB_name=DB_Detail2[1]) 

     data_DB1 = "C:\\SQL_Data\\DB_Data-%s_Output.txt" %(DB_Detail1[1]) 
     data_DB2 = "C:\\SQL_Data\\DB_Data-%s_Output.txt" %(DB_Detail2[1]) 

     with open(data_DB1, 'r') as f1, open(data_DB2, 'r') as f2: 
      if f1.read() == f2.read(): 
       print "Data of both DB Matches" 
      else: 
       print "Data of both DB Varies" 

は場合、あなたは正確な差があるものを手に入れるようにcompare_DB_Data()方法を改善したい、次のように、あなたは違いをダンプなる、それを再作成することができます別のテキストファイルにして、正確に違いが何であるかをチェックするように、あなたが後でそれを参照することができます: -

def compare_DB_Data(DB_Detail1=[], DB_Detail2=[]): 
    ''' 
    This method collects the data from both the given db and then compares the data 
    If any difference found, it appends the same into a file for post-verification 
    ''' 

    get_db_data(Instance_name=DB_Detail1[0], DB_name=DB_Detail1[1]) 
    get_db_data(Instance_name=DB_Detail2[0], DB_name=DB_Detail2[1]) 

    data_DB1 = "C:\\SQL_Data\\DB_Data-%s_Output.txt" %(DB_Detail1[1]) 
    data_DB2 = "C:\\SQL_Data\\DB_Data-%s_Output.txt" %(DB_Detail2[1]) 
    data_difference = "C:\\SQL_Data\\Data-Difference-%s-vs-%s_Output.txt" %(DB_Detail1[1], DB_Detail2[1]) 

    with open(data_difference, 'w') as f3: 
     f3.write("Data Difference in %s vs %s \n" %(DB_Detail1[1], DB_Detail2[1])) 
     f3.write("-"*100 + '\n') 
     f3.write(DB_Detail1[1]) 
     f3.write('\t\t\t\t\t\t\t') 
     f3.write(DB_Detail2[1] + '\n') 
     f3.write("-"*100 + '\n') 

    data_diff =0 
    with open(data_DB1, 'r') as f1, open(data_DB2, 'r') as f2: 
     for line_f1, line_f2 in zip(f1, f2): 
      if line_f1 != line_f2: 
       data_diff = 1 # Flag set if any difference found 
       with open(data_difference, 'a') as f3: 
        f3.write(line_f1.strip() + '\t\t\t\t\t\t\t' + line_f2.strip()) 

    if data_diff: 
     print "Data of both DB Varies" 
    else: 
     print "Data of both DB Matches" 
0

私は意図的にこの答えを追加しています。上記の答えは、SQLサーバーが存在する同じマシンで実行された場合にのみ機能します。そして、以前はテキストファイルを使用していましたが、これは2つのdbの完全な比較を保証しません。したがって、この新しい問題は、上記の問題を回避するための辞書ベースのアプローチです。

以下のコードは、SQLサーバーとコードが異なるマシン上にあっても機能します。しかし、そのためには、SQLサーバーが存在するマシン上でWINRMモジュールを有効にする必要があります。 WINRMは、Windowsマシン間で通信するための、ウィンドウの内蔵モジュールです。マシン上でWINRMを有効にするには、SQLマシンのコマンドラインで次のコマンドを実行する必要があります。

winrm qc -q 
winrm set winrm/config/client/auth @{Basic="true"} 
winrm set winrm/config/service/auth @{Basic="true"} 
winrm set winrm/config/service @{AllowUnencrypted="true"} 

これにより、マシン上にWINRMモジュールが有効になります。今我々はpywinrm私たちのリモートSQLホストとの通信のためのPythonのモジュールが必要になります。 pywinrmのインストールについてはthisリンクを参照してください。

ここではまず、データベースに存在するテーブルのリストを収集します(get_table_list_in_DBメソッドを使用します)。これらのテーブルをテキストファイルに格納します。このリストは、テーブルスキーマとすべてのデータベースに存在するテーブル。ファイルから各テーブル名を1つずつ読み込み、テーブルスキーマとテーブルデータを照会します。

get_db_Schema()メソッドは、上記の返されたテーブルリストを読み取り、get_table_Schema()メソッドを内部的に呼び出し、データベース内のすべてのテーブルのスキーマの詳細を収集します。各テーブルに対して返されるスキーマは、辞書のキーと値のペアとして格納されます。ここで、テーブル名はキーであり、返されるスキーマはvalueです。したがって、dbスキーマ全体は、各テーブルがkey、スキーマがvalueの辞書です。

同様に、get_db_data()get_table_data()が機能します。 get_db_data()は各テーブルのデータを収集し、テーブル名がkey、返されたデータがvalueの辞書に格納します。

2つのデータベースを比較するには、データベースの詳細(DB名とインスタンス名)をcompare_DB_Data()メソッドに渡します。これは両方のデータベースに対してget_db_Schema()を呼び出して比較します。両方のデータベースのスキーマが一致する場合は、get_db_data()メソッドを呼び出して両方のデータベースを照合し、一致させます。テーブルのスキーマとテーブルのデータをキーと値のペアの形式で格納しているため、DB1の各キー(スキーマとデータの両方)が両方のDBに同じ値を持つ場合、私たちのDBは同じです。

両方のDBのスキーマの相違が見つかった場合は、schema1_diff_schema2schema2_diff_schema1辞書に追加されます。同様に、データ差はdata1_diff_data2data2_diff_data1辞書に追加されます。以下

は同一のコード片である: -

class SQL_Compare_DB(object): 

    def __init__(self, SQL_Host_IP, auth): 
     # Append to path, in case not present 
     sys.path.append(r"C:\Program Files\Microsoft SQL Server\110\Tools\Binn") 
     # Create session with SQL host 
     self.session = winrm.Session(SQL_Host_IP, auth) 
     # We need a directory where the db files will be stored 
     if not os.path.exists("C:\SQL_Data"): 
      os.mkdir("C:\SQL_Data") 
     else: 
      os.system("RMDIR /S /Q C:\SQL_Data") 
      os.system("MKDIR C:\SQL_Data") 


    def get_table_list_in_DB(self, Instance_name, DB_name): 
     ''' 
     Returns the list of table in the given database 
     ''' 
     output_file = "C:\\SQL_Data\\Table_list_DB-%s_Output.txt" %(DB_name) 

     query = 'SELECT NAME from [%s].sys.tables' %(DB_name) 
     command = 'sqlcmd -S "%s" -Q "%s"' %(Instance_name, query) 

     execute_query = self.session.run_cmd(command) 
     if execute_query.std_err: 
      print "Error in command execution :- ", execute_query.std_err 
      return False 
     with open(output_file, 'w') as f: 
      f.write(execute_query.std_out) 
     return output_file 

    def get_db_Schema(self, Instance_name, DB_name): 
    ''' 
    Get the schema of all tables in the Database 
    ''' 
    table_list = self.get_table_list_in_DB(Instance_name, DB_name) 
    flag = 0 
    db_schema = {} 

    with open(table_list, 'r') as f1: 
     for lines in f1: 
      if re.match("^\s", lines): 
       flag = 0 
      if flag: 
       table_schema = self.get_table_Schema(
        Instance_name, DB_name, table_name=lines.strip()) 
       db_schema.update(table_schema) 
      if re.match("^----+?-", lines): 
       flag = 1 
    print db_schema 
    return db_schema 


def get_table_Schema(self, Instance_name, DB_name, table_name): 
    ''' 
    Get the table schema 
    ''' 
    table_schema = {} 
    query = """ 
    SELECT ORDINAL_POSITION, COLUMN_NAME, DATA_TYPE, 
    CHARACTER_MAXIMUM_LENGTH, IS_NULLABLE 
    FROM [%s].INFORMATION_SCHEMA.COLUMNS 
    WHERE TABLE_NAME = '%s'""".replace('\n','') %(DB_name, table_name) 

    command = 'sqlcmd -S "%s" -Q "%s"' %(Instance_name, query) 

    execute_query = self.session.run_cmd(command) 
    table_schema[table_name] = execute_query.std_out 
    if execute_query.std_err: 
     print "Error in command execution :- ", execute_query.std_err 
     return False 
    return table_schema 

def get_db_data(self, Instance_name, DB_name): 
    ''' 
    From the given DB, it fetchs the data of all existing 
    tables and append those in a single text file 
    ''' 
    db_data = {} 
    table_list = self.get_table_list_in_DB(Instance_name, DB_name) 

    flag = 0 
    with open(table_list, 'r') as f1: 
     for lines in f1: 
      if re.match("^\s", lines): 
       flag = 0 
      if flag: 
       table_data = self.get_table_data(
        Instance_name, DB_name, table_name=lines.strip()) 
       db_data.update(table_data) 
      if re.match("^----+?-", lines): # after the line ------ the tabel data are printed 
       flag = 1 

    print db_data 
    return db_data 

def get_table_data(self, Instance_name, DB_name, table_name): 
    ''' 
    Get the data for the given table 
    ''' 
    table_data = {} 

    query = "SELECT * from [%s].dbo.[%s]" %(DB_name, table_name) 
    command = 'sqlcmd -S "%s" -Q "%s"' %(Instance_name, query) 
    execute_query = self.session.run_cmd(command) 
    table_data[table_name] = execute_query.std_out 
    if execute_query.std_err: 
     print "Error in command execution :- ", execute_query.std_err 
     return False 
    return table_data 

def compare_DB_Data(self, DB_Detail1=[], DB_Detail2=[]): 
    ''' 
    Take detail of two DBs as input and gets the detailed DB data 
    The data collected are dumped into one dictionary and at last 
    both the dictionary are compared. 

    Arguments :- 
    DB_Detail1 :- a list of instance name and DB name for original DB 
    DB_Detail2 :- a list of instance name and DB name for Restored DB 
    e.g :- DB_Detail1 = ['Instance_name', 'Database_name'] 
    ''' 

    # Compare schema 
    db_schema1 = self.get_db_Schema(
     Instance_name=DB_Detail1[0], DB_name=DB_Detail1[1]) 
    db_schema2 = self.get_db_Schema(
     Instance_name=DB_Detail2[0], DB_name=DB_Detail2[1]) 
    schema1_diff_schema2 = {} 
    schema2_diff_schema1 = {} 


    print db_schema1 
    print db_schema2 
    set_current, set_past = set(db_schema1.keys()), set(db_schema2.keys()) 
    intersect = set_current.intersection(set_past) 
    added = set_current - intersect 
    removed = set_past - intersect 
    changed = set(k for k in intersect if db_schema2[k] != db_schema1[k]) 
    unchanged = set(k for k in intersect if db_schema2[k] == db_schema1[k]) 
    print added,removed,changed,unchanged 

    [schema1_diff_schema2.update(i) for i in [{m :db_schema1[m]} for m in added ]] 
    [schema1_diff_schema2.update(i) for i in [{m :db_schema1[m]} for m in changed]] 
    [schema2_diff_schema1.update(i) for i in [{m :db_schema2[m]} for m in removed]] 
    [schema2_diff_schema1.update(i) for i in [{m :db_schema2[m]} for m in changed]] 

    if added == set([]) and removed == set([]) and changed == set([]): 
     print "Schema of both DB Matches" 
    else: 
     print "Schema of both DB Varies" 


    # Compare data 
    data_DB1 = self.get_db_data(
     Instance_name=DB_Detail1[0], DB_name=DB_Detail1[1]) 
    data_DB2 = self.get_db_data(
     Instance_name=DB_Detail2[0], DB_name=DB_Detail2[1]) 
    data1_diff_data2 = {} 
    data2_diff_data1 = {} 

    set_current_data, set_past_data = set(data_DB1.keys()), set(data_DB2.keys()) 
    intersect = set_current_data.intersection(set_past_data) 
    added = set_current_data - intersect 
    removed = set_past_data - intersect 
    changed = set(k for k in intersect if data_DB2[k] != data_DB1[k]) 
    unchanged = set(k for k in intersect if data_DB2[k] == data_DB1[k]) 
    print added,removed,changed,unchanged 


    [data1_diff_data2.update(i) for i in [{m :data_DB1[m]} for m in added ]] 
    [data1_diff_data2.update(i) for i in [{m :data_DB1[m]} for m in changed]] 
    [data2_diff_data1.update(i) for i in [{m :data_DB2[m]} for m in removed]] 
    [data2_diff_data1.update(i) for i in [{m :data_DB2[m]} for m in changed]] 

    print "Diff DB1 vs DB2 :- ", data1_diff_data2 
    print "Diff DB1 vs DB2 :- ", data2_diff_data1 

    if added == set([]) and removed == set([]) and changed == set([]): 
     print "Data of both DB Matches" 
    else: 
     print "Data of both DB Varies" 
関連する問題