Python如何查看兩個(gè)數(shù)據(jù)庫(kù)的同名表的字段名差異
查看兩個(gè)數(shù)據(jù)庫(kù)的同名表的字段名差異
問(wèn)題描述
開(kāi)發(fā)過(guò)程中有多個(gè)測(cè)試環(huán)境,測(cè)試環(huán)境 A 加了字段,測(cè)試環(huán)境 B 忘了加,字段名對(duì)不上,同一項(xiàng)目就報(bào)錯(cuò)了
CREATE DATABASE `a` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'; CREATE DATABASE `b` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'; USE `a`; CREATE TABLE `student` ( `id` int(11) AUTO_INCREMENT, `class_id` int(11) DEFAULT NULL, `name` varchar(255), `birthday` date, `chinese` int(11), `math` int(11), `english` int(11), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; USE `b`; CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `class_id` int(11) DEFAULT NULL, `name` varchar(255) DEFAULT NULL, `birthday` date DEFAULT NULL, `gender` tinyint(4) DEFAULT NULL, `chinese` int(11) DEFAULT NULL, `math` int(11) DEFAULT NULL, `english` int(11) DEFAULT NULL, `physics` int(11) DEFAULT NULL, `chemistry` int(11) DEFAULT NULL, `biology` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_class_id` (`class_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
解決方案
安裝
pip install SQLAlchemy pip install pymysql
代碼
from collections import defaultdict import sqlalchemy from sqlalchemy.engine.reflection import Inspector def get_table_column_map(inspector: Inspector): """獲取數(shù)據(jù)庫(kù)中所有表對(duì)應(yīng)的字段""" table_column_map = defaultdict(set) table_names = inspector.get_table_names() for table_name in table_names: columns = inspector.get_columns(table_name) # 字段信息 # indexes = inspect.get_indexes(table_name) # 索引信息 for column in columns: table_column_map[table_name].add(column['name']) return table_column_map def compare_table_column_difference(a, b): """對(duì)比同名表字段的差異""" table_names = set(a) & set(b) # 同名表 for table_name in table_names: columns_a = a[table_name] columns_b = b[table_name] difference = columns_a ^ columns_b if difference: print(table_name, difference) engine = sqlalchemy.create_engine('mysql+pymysql://root:123456@127.0.0.1:3306/a') engine1 = sqlalchemy.create_engine('mysql+pymysql://root:123456@127.0.0.1:3306/b') inspector = sqlalchemy.inspect(engine) inspector1 = sqlalchemy.inspect(engine1) table_column_map = get_table_column_map(inspector) table_column_map1 = get_table_column_map(inspector1) compare_table_column_difference(table_column_map, table_column_map1) # student {'gender', 'chemistry', 'physics', 'biology'}
mysql-utilities
也可以使用專門的工具——mysql-utilities 中的 mysqldiff
文檔
mysqldiff --help
命令
mysqldiff --server1=user:pass@host:port --server2=user:pass@host:port db1.object1:db2.object1
例子
mysqldiff --server1=root:123456@127.0.0.1:3306 --server2=root:123456@127.0.0.1:3306 a.student:b.student
效果
--- a.student +++ b.student @@ -3,8 +3,13 @@ `class_id` int(11) DEFAULT NULL, `name` varchar(255) DEFAULT NULL, `birthday` date DEFAULT NULL, + `gender` tinyint(4) DEFAULT NULL, `chinese` int(11) DEFAULT NULL, `math` int(11) DEFAULT NULL, `english` int(11) DEFAULT NULL, - PRIMARY KEY (`id`) + `physics` int(11) DEFAULT NULL, + `chemistry` int(11) DEFAULT NULL, + `biology` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `idx_class_id` (`class_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8
優(yōu)點(diǎn):比較內(nèi)容更詳盡
缺點(diǎn):無(wú)法批量,要自己指定比較對(duì)象(稍微改寫即可克服)
Python數(shù)據(jù)庫(kù)之間差異對(duì)比
此腳本用于兩個(gè)數(shù)據(jù)庫(kù)之間的表、列、欄位、索引的差異對(duì)比。
cat oracle_diff.py #!/home/dba/.pyenv/versions/3.5.2/bin/python #coding=utf-8 import cx_Oracle import time import difflib import os v_host=os.popen('echo $HOSTNAME') class Oracle_Status_Output(): ? ? def __init__(self,username,password,tns): ? ? ? ? try: ? ? ? ? ? ? self.db = cx_Oracle.connect(username,password,tns) ? ? ? ? ? ? self.cursor = self.db.cursor() ? ? ? ? except Exception as e: ? ? ? ? ? ? print('Wrong') ? ? ? ? ? ? print(e) ? ? def schemas_tables_count(self,sql,db): ? ? ? ? try: ? ? ? ? ? ? ? self.cursor.execute(sql) ? ? ? ? ? ? v_result=self.cursor.fetchall() ? ? ? ? ? ? #print(v_result) ? ? ? ? ? ? count = 0 ? ? ? ? ? ? for i in range(len(v_result)): ? ? ? ? ? ? ? ? #print(v_result[i][1],'--',v_result[i][0]) ? ? ? ? ? ? ? ? count = int(v_result[i][0]) + count ? ? ? ? ? ? print(db,'Count Tables','--',count) ? ? ? ? except Exception as e: ? ? ? ? ? ? print('Wrong--schemas_tables_count()') ? ? ? ? ? ? print(e) ? ? def schemas_tables_list(self,sql): ? ? ? ? try: ? ? ? ? ? ? self.cursor.execute(sql) ? ? ? ? ? ? v_result=self.cursor.fetchall() ? ? ? ? ? ? #print(v_result) ? ? ? ? ? ? return v_result ? ? ? ? except Exception as e: ? ? ? ? ? ? print('Wrong--schemas_tables_list()') ? ? ? ? ? ? print(e) ? ? def schemas_tables_columns_list(self,sql,data): ? ? ? ? try: ? ? ? ? ? ? self.cursor.execute(sql,A=data) ? ? ? ? ? ? v_result=self.cursor.fetchall() ? ? ? ? ? ? return v_result ? ? ? ? except Exception as e: ? ? ? ? ? ? print('schemas_tables_columns_list') ? ? ? ? ? ? print(e) ? ? def schemas_tables_indexes_list(self,sql,data): ? ? ? ? try: ? ? ? ? ? ? self.cursor.execute(sql,A=data) ? ? ? ? ? ? v_result=self.cursor.fetchall() ? ? ? ? ? ? return v_result ? ? ? ? except Exception as e: ? ? ? ? ? ? print('schemas_tables_indexes_list') ? ? ? ? ? ? print(e) ? ? def close(self): ? ? ? ? self.db.close() schemas_tables_count_sql = "SELECT COUNT(1),S.OWNER FROM DBA_TABLES S WHERE S.OWNER in ('PAY','BOSS','SETTLE','ISMP','TEMP_DSF','ACCOUNT') GROUP BY S.OWNER" schemas_tables_list_sql ?= "SELECT S.OWNER||'.'||S.TABLE_NAME FROM DBA_TABLES S WHERE S.OWNER in ('PAY','BOSS','SETTLE','ISMP','TEMP_DSF','ACCOUNT')" schemas_tables_columns_sql = "select a.OWNER||'.'||a.TABLE_NAME||'.'||a.COLUMN_NAME||'.'||a.DATA_TYPE||'.'||a.DATA_LENGTH from dba_tab_columns a where a.OWNER||'.'||a.TABLE_NAME = :A" schemas_tables_indexes_sql = "SELECT T.table_owner||'.'||T.table_name||'.'||T.index_name FROM DBA_INDEXES T WHERE T.table_owner||'.'||T.table_name = :A" jx_db ?= Oracle_Status_Output('dbadmin','QazWsx12','106.15.109.134:1522/paydb') pro_db = Oracle_Status_Output('dbadmin','QazWsx12','localhost:1521/paydb') jx_db.schemas_tables_count(schemas_tables_count_sql,'JX ') pro_db.schemas_tables_count(schemas_tables_count_sql,'PRO') jx_schemas_tables ?= jx_db.schemas_tables_list(schemas_tables_list_sql) pro_schemas_tables = pro_db.schemas_tables_list(schemas_tables_list_sql) #print(jx_schemas_tables) #print(pro_schemas_tables) def diff_jx_pro(listA,listB,listClass): ? ? if listA !=[] and listB !=[]: ? ? ? ? #listD ?= list(set(listA).union(set(listB))) ? ? ? ? listC ?= sorted(list(set(listA).intersection(set(listB)))) ? ? ? ? listAC = sorted(list(set(listA).difference(set(listC)))) ? ? ? ? listBC = sorted(list(set(listB).difference(set(listC)))) ? ? ? ? #if sorted(listD) == sorted(listC): ? ? ? ? # ? ?print('All Tables OK') ? ? ? ? if listC == []: ? ? ? ? ? ? #print('JX ',listClass,':',listA) ? ? ? ? ? ? #print('PRO ',listClass,':',listB) ? ? ? ? ? ? print('Intersection>>','JX ',listClass,':',listAC,'--->','PRO',listClass,':',listBC) ? ? ? ? elif listAC != [] or listBC != []: ? ? ? ? ? ? print('Difference ?>>','JX ',listClass,':',listAC,'--->','PRO',listClass,':',listBC) ? ? ? ? else: ? ? ? ? ? ? pass ? ? ? ? return listC ? ? ? ? if __name__ == '__main__': ? ? #diff_jx_pro(jx_schemas_tables,pro_schemas_tables) ? ? tables_lists = diff_jx_pro(jx_schemas_tables,pro_schemas_tables,'Tables') ? ? for i in range(len(tables_lists)): ? ? ? ? table_name = "".join(tuple(tables_lists[i])) ? ? ? ? #print(table_name) ? ? ? ? jx_schemas_tables_columns = jx_db.schemas_tables_columns_list(schemas_tables_columns_sql,table_name) ? ? ? ? pro_schemas_tables_columns = pro_db.schemas_tables_columns_list(schemas_tables_columns_sql,table_name) ? ? ? ? diff_jx_pro(jx_schemas_tables_columns,pro_schemas_tables_columns,'Columns') ? ? for i in range(len(tables_lists)): ? ? ? ? table_name = "".join(tuple(tables_lists[i])) ? ? ? ? #print(table_name) ? ? ? ? jx_schemas_tables_indexes = jx_db.schemas_tables_indexes_list(schemas_tables_indexes_sql,table_name) ? ? ? ? pro_schemas_tables_indexes = pro_db.schemas_tables_indexes_list(schemas_tables_indexes_sql,table_name) ? ? ? ? diff_jx_pro(jx_schemas_tables_indexes,pro_schemas_tables_indexes,'Indexes') ? ? jx_db.close() ? ? pro_db.close() ? ? print('------------Table, column and index check completed--------------')
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Pycharm學(xué)習(xí)教程(7)虛擬機(jī)VM的配置教程
這篇文章主要為大家詳細(xì)介紹了最全的Pycharm學(xué)習(xí)教程第七篇,Python快捷鍵相關(guān)設(shè)置,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05解決PyCharm的Python.exe已經(jīng)停止工作的問(wèn)題
今天小編就為大家分享一篇解決PyCharm的Python.exe已經(jīng)停止工作的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-11-11pip版本低引發(fā)的python離線包安裝失敗的問(wèn)題
這篇文章主要介紹了pip版本低引發(fā)的python離線包安裝失敗的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09使用Python的Flask框架表單插件Flask-WTF實(shí)現(xiàn)Web登錄驗(yàn)證
Flask處理表單除了本身的WTForms包,使用Flask-WTF擴(kuò)展來(lái)增強(qiáng)表單功能也是很多開(kāi)發(fā)者的選擇,這里我們就來(lái)講解如何使用Python的Flask框架表單插件Flask-WTF實(shí)現(xiàn)Web登錄驗(yàn)證2016-07-07Python實(shí)現(xiàn)常見(jiàn)數(shù)據(jù)格式轉(zhuǎn)換的方法詳解
這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)常見(jiàn)數(shù)據(jù)格式轉(zhuǎn)換的方法,主要是xml_to_csv和csv_to_tfrecord,感興趣的小伙伴可以了解一下2022-09-09Python+OpenCV檢測(cè)燈光亮點(diǎn)的實(shí)現(xiàn)方法
這篇文章主要介紹了Python+OpenCV檢測(cè)燈光亮點(diǎn)的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11