利用Python解决MySQL视图导入导出依赖的问题
本文介绍如何使用Python脚本解决Navicat导入MySQL视图时因依赖顺序导致的报错问题。通过查询information_schema.VIEWS获取视图定义,利用迭代算法重新排序视图创建语句,确保被依赖视图先创建,从而自动化生成正确的SQL导出文件。
视图
视图是一种虚拟表,它并不实际存储数据,而是基于SQL查询语句动态生成的数据集。用户只需引用视图名称即可获取结果集,并在操作中将其视为普通表使用。
创建视图
以下代码展示如何创建一个名为v1的视图,该视图用于查询color表中的所有数据。
CREATE VIEW v1 AS SELECT * FROM color;
查看视图
在使用视图时,可以像操作普通表一样对其进行查询。需要注意的是,由于视图是虚拟的,不能直接通过视图对底层真实表执行创建、更新或删除操作,仅支持查询功能。
select * from v1; -- 等于执行SELECT * FROM color
输出结果
+-----+--------+ | nid | title | +-----+--------+ | 1 | red | | 2 | yellow | +-----+--------+ 2 rows in set (0.00 sec)
修改视图
ALTER VIEW v1 AS SELECT * FROM color WHERE nid = 1;
删除视图
DROP VIEW v1;
引用
Navicat是MySQL可视化工具中较为优秀的选择,但在处理视图的导入导出时,它默认按照视图名称的字母顺序进行处理。如果视图之间存在依赖关系,这种顺序可能导致导入时报错。这一问题曾让我在使用Docker部署MySQL时得以规避,但近期不得不直接面对,因此编写了一个小工具来解决此依赖问题。
整体思路
MySQL中查询所有视图及其定义非常容易。因此,可以编写一个视图导出工具,在存储时调整各视图的保存位置,优先处理依赖关系:将被依赖的视图放在前面。这样即可解决导入时的依赖顺序错误问题。
获取视图信息
执行以下查询语句,即可获取当前数据库中所有视图的详细信息。
select * from information_schema.VIEWS where TABLE_SCHEMA = DatabaseName
查询结果字段说明:
- TABLE_NAME:数据库中视图的名称
- VIEW_DEFINITION:视图的定义代码,仅包含查询语句部分
- DEFINER:视图定义者(创建者)的名称
- SECURITY:安全级别设置
综上所述,所有视图的信息均保存在该表中。为了完成任务,只需提取TABLE_NAME和VIEW_DEFINITION这两个字段即可。
算法描述
- 将查询结果存入字典,以视图名称为键(key),视图定义为值(value)。
- 编写处理依赖关系的函数process_rely,输入参数rely_old为包含所有视图名称的数组,返回值为按依赖关系调整顺序后的视图名称数组。这样设计是考虑到依赖关系复杂时,单次迭代可能无法完全处理,可能需要递归调用或多次迭代。
process_rely函数算法描述:
第一层循环,从rely_old中依次取出一个视图名称。
第二层循环,从字典中依次取出一个键值对。
判断第二层的键值是否被第一层元素的定义所依赖。
如果该键值尚未存在于结果数组中,则继续处理。
检查第一层元素是否已存在于结果数组中。
若第一层元素不在结果数组中,则将当前键值追加到结果数组末尾。
若第一层元素已在结果数组中,则执行下一步操作。
将当前键值插入到第一层元素之前,以保证依赖顺序。
如果键值已经存在于结果数组中,则进入位置调整逻辑。
若第一层元素也在结果数组中,则需调整两者的相对位置。
分别查找第一层元素和键值在结果数组中的索引位置。
如果第一层元素的索引大于键值的索引(即第一层元素在键值之后)。
将键值移动到第一层元素之前,以修正依赖顺序。
当第二层循环结束时,检查第一层元素是否仍未出现在结果集中。
如果第一层元素仍不在结果集中,则将其追加到结果集末尾。
返回最终调整好的结果集。
上述说明基于Python代码逻辑。幸运的是,该算法一次迭代即可处理复杂的依赖关系。在编写初期,若依赖算法不完善,通过多次迭代也能解决复杂依赖。这增强了完成该任务的信心,最终成功实现了功能。
完整代码
import pymysql
conn = pymysql.connect(host='172.17.0.1', port=3306, user='root',
passwd='123456', db='database', charset='utf8mb4')
def process_rely(parmas={}, rely_old=[]):
_rely = []
_keys = list(parmas.keys())
for k in rely_old:
for bl in _keys:
if str(parmas[k]).find(bl) > -1:
if bl not in _rely:
if k not in _rely:
_rely.append(bl)
else:
i = _rely.index(k)
_rely.insert(i, bl)
else:
if k in _rely:
i = _rely.index(k)
j = _rely.index(bl)
if i < j:
del _rely[j]
_rely.insert(i, bl)
if k not in _rely:
_rely.append(k)
return _rely
cur = conn.cursor()
cur.execute('select TABLE_NAME, VIEW_DEFINITION from information_schema.VIEWS where TABLE_SCHEMA = %s ', 'database')
rs = cur.fetchall()
cur.close()
conn.close()
ps = {}
for al in rs:
ps['`' + al[0] + '`'] = al[1]
rely = process_rely(ps, list(ps.keys()))
# rely = process_rely(ps, rely1)
file_object = open('view.sql', 'w')
for al in rely:
file_object.write('DROP VIEW IF EXISTS ' + al + ';\n')
file_object.write('CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`%` SQL SECURITY DEFINER VIEW ' + al +
' AS ' + ps[al] + ';\n\n')
file_object.close()
小结
思路要清晰,代码需逐步逼近最终目标,积跬步以至千里。在开发此工具时,起初觉得依赖关系处理繁琐,尤其是深层依赖可能一次无法处理完毕。正是采用了迭代思想,最终实现了单次迭代解决所有问题的完美结局。
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对本站的支持。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













