網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
查看兩個(gè)數(shù)據(jù)庫(kù)的同名表的字段名差異
問題描述
開發(fā)過程中有多個(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--------------')
原文鏈接:https://xercis.blog.csdn.net/article/details/124410922
相關(guān)推薦
- 2022-09-24 Go?select使用與底層原理講解_Golang
- 2022-10-26 Pytorch中torch.stack()函數(shù)的深入解析_python
- 2023-03-25 python?中?關(guān)于reverse()?和?reversed()的用法詳解_python
- 2023-05-12 Python時(shí)間戳轉(zhuǎn)換為字符串與字符串轉(zhuǎn)換為時(shí)間戳_python
- 2024-02-25 maven打包測(cè)試jar包沖突
- 2022-06-01 React函數(shù)式組件與類組件的不同你知道嗎_React
- 2022-07-11 Android星級(jí)評(píng)分條實(shí)現(xiàn)評(píng)分界面_Android
- 2022-12-23 Android同步異步任務(wù)與多線程及Handler消息處理機(jī)制基礎(chǔ)詳細(xì)講解_Android
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支