数据库版本更新后,有新增的表,新增的字段
通过对比两个库的差异,然后生成语句补充差异

import MySQLdb
import datetime

# 进行对比的数据库(新库)
db1 = ""
# 要更新的数据库(旧库)
db2 = ""

sql_host = '127.0.0.1'
sql_port = 3306
sql_user = 'root'
sql_pwd = '='
sql_charset = 'utf8'

# 数据需要更新的表
table_list = []
# table_list = []
conn = MySQLdb.connect(host=sql_host, port=sql_port, user=sql_user, passwd=sql_pwd, db=db1, charset=sql_charset)
# 获取游标
cur = conn.cursor()

text = ""

# 两个数据库相同的表要更新字段的数据类型(db1与db2相同的表和字段,字段的数据类型不同)
sql = f"""
select distinct * from (SELECT DISTINCT
    table_name ,column_name, column_comment, column_type, is_nullable, column_default, extra
FROM
    information_schema.columns
WHERE
    table_schema = '{db1}') t1
left join (
SELECT DISTINCT
    table_name ,column_name ,column_comment ,column_type, is_nullable, column_default, extra
FROM
    information_schema.columns
WHERE
    table_schema = '{db2}') t2
on t1.table_name = t2.table_name and t1.column_name=t2.column_name 
where t1.column_type!=t2.column_type OR t1.is_nullable!=t2.is_nullable or t1.column_default!=t2.column_default or t1.extra!=t2.extra
"""
cur.execute(sql)
l1 = []
while 1:
    res = cur.fetchone()
    if res is None:
        break  # 表示已经取完结果集s
    l1.append(res)
# print('l1')
# print(l1)
# 对更新数据类型的sql语句进行拼接
for i in l1:
    table_name = i[0]  # 表名
    column_name = i[1]  # 字段名
    column_comment = i[2]  # 备注
    column_type = i[3]  # 字段类型
    is_nullable = i[4]  # 字段是否为空
    column_default = i[5]  # 默认值
    extra = i[6]  # 自动递增,更新时间等

    # 默认值
    default_ = 'DEFAULT NULL' if column_default is None else f'DEFAULT {column_default}'
    # 字段是否为空
    if is_nullable == 'YES':
        is_nullable_ = 'NULL'
    else:
        is_nullable_ = 'NOT NULL'
        # 当该字段为非空时,判断默认值是否为空,如果是则清除默认值
        default_ = '' if column_default is None else default_
    # 备注
    column_comment_ = f" COMMENT '{column_comment}'" if column_comment else ''

    sql = f"ALTER TABLE `{table_name}` MODIFY COLUMN `{column_name}` {column_type} {is_nullable_} {default_} {extra}{column_comment_};"
    # sql = f"ALTER TABLE {table_name} MODIFY COLUMN {column_name} {column_type};"
    # print(sql)
    text = text + sql + "\n"

# 两个数据库相同表,需要更新的数据库要添加的表字段(db1中的表,db2中存在但是缺少字段)
sql2 = f"""
SELECT DISTINCT * from (SELECT DISTINCT 
    t1.table_name,t1.column_name,t1.column_type,t1.column_comment, t1.is_nullable, t1.column_key, 
    t1.column_default, t1.extra, t1.character_set_name, t1.collation_name
from (SELECT DISTINCT
    table_name,column_name,column_comment,column_type, is_nullable, column_key, 
    column_default, extra, character_set_name, collation_name
FROM
   information_schema.columns
WHERE
    table_schema = '{db1}') t1
left join (SELECT DISTINCT
    table_name,column_name,column_comment,column_type
FROM
    information_schema.columns
WHERE
    table_schema = '{db2}') t2
on t1.table_name = t2.table_name and t1.column_name=t2.column_name where t2.table_name is null) t3 left join 
(select distinct t1.table_name from (SELECT DISTINCT
    table_name,column_name,column_comment,column_type
FROM
    information_schema.columns
WHERE
    table_schema = '{db1}') t1
left join (SELECT DISTINCT
    table_name,column_name,column_comment,column_type
FROM
    information_schema.columns
WHERE
    table_schema = '{db2}') t2
on t1.table_name = t2.table_name where t2.table_name is null) t4 on t3.table_name=t4.table_name where t4.table_name is null
"""
cur.execute(sql2)
l2 = []
l2_ = []
while 1:
    res = cur.fetchone()
    if res is None:
        break  # 表示已经取完结果集s
    l2.append(res)
    l2_.append((res[0], res[1]))
# print('l2')
# print(l2_)
# 对需要新增字段的sql语句进行拼接.
for i in l2:
    table_name = i[0]  # 表名
    column_name = i[1]  # 字段名
    column_type = i[2]  # 字段类型
    column_comment = i[3]  # 备注
    is_nullable = i[4]  # 字段是否为空
    column_key = i[5]  # 字段的主键(PRI为主键)
    column_default = i[6]  # 默认值
    extra = i[7]  # 自动递增,更新时间等
    character_set_name = i[8]  # 字符集
    collation_name = i[9]  # 排序规则
    # 默认值
    default_ = 'DEFAULT NULL' if column_default is None else f'DEFAULT {column_default}'
    # 字段是否为空
    if is_nullable == 'YES':
        is_nullable_ = 'NULL'
    else:
        is_nullable_ = 'NOT NULL'
        # 当该字段为非空时,判断默认值是否为空,如果是则清除默认值
        default_ = '' if column_default is None else default_

    # varchar类型的编码
    character_ = f' CHARACTER SET {character_set_name} COLLATE {collation_name}' if character_set_name else ''
    # 备注
    column_comment_ = f" COMMENT '{column_comment}'" if column_comment else ''

    sql = f"ALTER TABLE `{table_name}` ADD COLUMN `{column_name}` {column_type}{character_} {is_nullable_} {default_} {extra}{column_comment_};"
    # print(sql)
    text = text + sql + "\n"

# 需要更新的数据库中需要新建的表(db1中有的表,db2中没有的)
sql3 = f"""
select table_name from information_schema.tables where table_schema='{db1}' and table_name not in (
select table_name from information_schema.tables where table_schema='{db2}') 
"""
cur.execute(sql3)
l3 = []
while 1:
    res = cur.fetchone()
    if res is None:
        break  # 表示已经取完结果集s
    l3.append(res)
# print('l3')
# print(l3)
# 获取新建表的sql建表语句
for i in l3:
    table_name = i[0]
    cur.execute(f"show create table {table_name}")
    l4 = []
    while 1:
        res = cur.fetchone()
        if res is None:
            break  # 表示已经取完结果集s
        l4.append(res)
    # print(len(l4))
    # print(l4[0][1] + ";")
    text += f"""
-- ----------------------------
-- Table structure for {l4[0][0]}
-- ----------------------------
"""
    text += l4[0][1] + ";" + "\n"


# 添加新的外键
sql5 = f"""
SELECT * FROM ( SELECT DISTINCT
    table_name,column_name,referenced_table_name,referenced_column_name,position_in_unique_constraint
FROM
    information_schema.key_column_usage
WHERE
    table_schema = '{db1}' and position_in_unique_constraint = 1
    ) t1 LEFT JOIN ( SELECT DISTINCT
    table_name,column_name,referenced_table_name,referenced_column_name,position_in_unique_constraint
FROM 
    information_schema.key_column_usage
WHERE
    table_schema = '{db2}' and position_in_unique_constraint = 1
    ) t2 ON t1.table_name = t2.table_name AND t1.column_name = t2.column_name
    WHERE  t2.column_name is null and t1.table_name not in (
    select table_name from information_schema.tables where table_schema='{db1}' and table_name not in (
    select table_name from information_schema.tables where table_schema='{db2}'));
"""
cur.execute(sql5)
l5 = []
while 1:
    res = cur.fetchone()
    if res is None:
        break  # 表示已经取完结果集s
    l5.append(res)
# print('l5')
# print(l5)
# 需要更新的数据库中需要补充的外键
text += f'''\nSET foreign_key_checks = 0;\n'''
for i in l5:
    table_name = i[0]  # 表名
    column_name = i[1]  # 字段名
    referenced_table_name = i[2]  # 关联的表名
    referenced_column_name = i[3]  # 关联的字段名
    position_in_unique_constraint = i[4]  # 关联的字段名
    if position_in_unique_constraint == 1:
        text += f'''ALTER TABLE `{table_name}`ADD  FOREIGN KEY(`{column_name}`) REFERENCES `{referenced_table_name}`(`{referenced_column_name}`) ON DELETE CASCADE ON UPDATE CASCADE;\n'''
text += '''SET foreign_key_checks = 1;\n'''  # 添加外键约束

# 更新规则,解析器等固定数据表的数据
text += '''\n-- 覆盖插入数据,先清楚外键约束,等数据更新完成之后再添加外键约束\nSET foreign_key_checks = 0;\n'''  # 删除外键约束
for table_name in table_list:
    text += f'''
-- ----------------------------
-- Records of {table_name}
-- ----------------------------
truncate table {table_name};
'''
    sql = f'''SELECT * FROM {table_name}'''
    cur.execute(sql)
    field_name_list = '('
    for i, field_name in enumerate(cur.description):
        if i == len(cur.description) - 1:
            field_name_list += f'{table_name}.{field_name[0]}'
        else:
            field_name_list += f'{table_name}.{field_name[0]}, '
    field_name_list += ')'
    while 1:
        res = cur.fetchone()
        if res is None:
            # 表示已经取完结果集s
            break
        new_res = []
        for i in res:
            if type(i) == datetime.datetime:
                new_res.append(i.strftime("%Y-%m-%d %H:%M:%S"))
            else:
                new_res.append(i)
        text += f'''INSERT INTO `{table_name}` {field_name_list}  VALUES {tuple(new_res)};\n'''.replace(', None',
                                                                                                        ', Null')
text += '''SET foreign_key_checks = 1;\n'''  # 添加外键约束

# 调用方法写入同目录文件中
with open("gengxin.sql", "w", encoding="utf-8") as fp:
    fp.write(text)

cur.close()
conn.commit()
conn.close()
print('sql生成成功')


# 执行更新的sql语句
conn2 = MySQLdb.connect(host=sql_host, port=sql_port, user=sql_user, passwd=sql_pwd, db=db2, charset=sql_charset)
cur2 = conn2.cursor()
cur2.execute(text)
cur2.close()
conn2.commit()
conn2.close()
print('sql执行成功')