私は意図的にこの答えを追加しています。上記の答えは、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_schema2
schema2_diff_schema1
辞書に追加されます。同様に、データ差はdata1_diff_data2
とdata2_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"