万普插件库

jQuery插件大全与特效教程

Python自动化比较两个数据库表的结构和数据,精准发现差异!

引言:

比较两个数据库中多个表的结构和数据差异,并将比较结果保存到一个文本文件中。

代码如下:

import pymssql
import pandas as pd

class DatabaseComparer:
    def __init__(self, conn_params_db1, conn_params_db2):
        """
        初始化DatabaseComparer对象,接受两个数据库的连接参数。
        :param conn_params_db1: 第一个数据库的连接参数
        :param conn_params_db2: 第二个数据库的连接参数
        """
        self.conn_params_db1 = conn_params_db1
        self.conn_params_db2 = conn_params_db2

    def get_connection(self, params):
        """ 获取数据库连接 """
        return pymssql.connect(
            server=params['server'],
            user=params['user'],
            password=params['password'],
            database=params['database']
        )

    def get_table_columns(self, conn, table_name):
        """ 获取表字段信息 """
        query = f"""
            SELECT COLUMN_NAME, DATA_TYPE
            FROM INFORMATION_SCHEMA.COLUMNS
            WHERE TABLE_NAME = '{table_name}'
        """
        return pd.read_sql(query, conn)

    def compare_table_columns(self, table_name):
        """ 比较两个数据库表的结构 """
        conn1 = self.get_connection(self.conn_params_db1)
        conn2 = self.get_connection(self.conn_params_db2)
        
        columns_db1 = self.get_table_columns(conn1, table_name)
        columns_db2 = self.get_table_columns(conn2, table_name)
        
        conn1.close()
        conn2.close()

        #todo 找出差异
        diff_columns_db1 = columns_db1[~columns_db1['COLUMN_NAME'].isin(columns_db2['COLUMN_NAME'])]
        diff_columns_db2 = columns_db2[~columns_db2['COLUMN_NAME'].isin(columns_db1['COLUMN_NAME'])]
        
        return diff_columns_db1, diff_columns_db2

    def compare_table_data(self, table_name):
        """ 比较两个数据库表的数据 """
        conn1 = self.get_connection(self.conn_params_db1)
        conn2 = self.get_connection(self.conn_params_db2)
        
        query_db1 = f"SELECT * FROM {table_name}"
        query_db2 = f"SELECT * FROM {table_name}"
        
        df1 = pd.read_sql(query_db1, conn1)
        df2 = pd.read_sql(query_db2, conn2)
        
        conn1.close()
        conn2.close()

        #todo 使用 concat 找出不同的行
        diff = pd.concat([df1, df2]).drop_duplicates(keep=False)
        
        return diff

    def compare_and_save_to_txt(self, table_names, output_filename):
        """
        比较多个表的结构和数据,并将比较结果保存到 txt 文件中。
        :param table_names: 需要比较的表名列表
        :param output_filename: 输出的txt文件名
        """
        with open(output_filename, 'w') as f:
            for table_name in table_names:
                print(f"正在比较表: {table_name}")

                #todo 比较表结构
                diff_columns_db1, diff_columns_db2 = self.compare_table_columns(table_name)

                #todo 比较表数据
                diff_data = self.compare_table_data(table_name)

                #todo 写入表名(仅在存在差异时)
                changes_found = False

                #todo 写入表结构差异
                if not diff_columns_db1.empty or not diff_columns_db2.empty:
                    changes_found = True
                    f.write(f"\n\n=== 正在比较表: {table_name} ===\n")
                    
                    if not diff_columns_db1.empty:
                        f.write("\n--- DB1 中有,但 DB2 中没有的列 ---\n")
                        for _, row in diff_columns_db1.iterrows():
                            f.write(f"列名: {row['COLUMN_NAME']}, 数据类型: {row['DATA_TYPE']} (DB1)\n")
                    
                    if not diff_columns_db2.empty:
                        f.write("\n--- DB2 中有,但 DB1 中没有的列 ---\n")
                        for _, row in diff_columns_db2.iterrows():
                            f.write(f"列名: {row['COLUMN_NAME']}, 数据类型: {row['DATA_TYPE']} (DB2)\n")

                #todo 写入表数据差异
                if not diff_data.empty:
                    changes_found = True
                    f.write("\n--- DB1 和 DB2 之间的不同数据行 ---\n")
                    diff_data_str = diff_data.to_string(index=False)
                    f.write(diff_data_str + "\n")
                
                #todo 如果没有任何差异,则不输出该表的内容
                if not changes_found:
                    f.write(f"\n表 {table_name} 没有发现差异\n")

        print(f"比较结果已保存到 {output_filename}")

#todo 使用示例
if __name__ == "__main__":
    #todo 设置数据库连接参数
    conn_params_db1 = {
        'server': '127.0.0.1',
        'user': 'user',
        'password': 'password',
        'database': 'db1'
    }
    
    conn_params_db2 = {
        'server': '127.0.0.2',
        'user': 'user',
        'password': 'password',
        'database': 'db2'
    }
    
    comparer = DatabaseComparer(conn_params_db1, conn_params_db2)
    
    #todo 指定多个表名进行比较
    table_names = ['table1', 'table2', 'table3']
    
    #todo 输出文件名
    output_filename = 'comparison_results_filtered.txt'

    #todo 执行比较并保存结果
    comparer.compare_and_save_to_txt(table_names, output_filename)

注意事项:

  • 结果格式:当前代码将比较结果输出到文本文件中,格式较为简单。对于大量数据的比较,可能需要考虑更为结构化的输出格式(如 CSV、JSON 或 Excel),这样可以方便后续的分析或处理。
  • 性能问题:pandas.read_sql() 会一次性从数据库读取表的所有数据,如果表数据量很大,可能会导致内存问题或性能瓶颈。可以考虑限制查询的数据量(如分页查询,或者通过 WHERE 子句指定过滤条件)。
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言