晚上8点在地铁上收到boss需求:把400多张表的关系画出来明早客户要!

简介: 晚上8点在地铁上收到boss需求:把400多张表的关系画出来明早客户要!

1、故事背景

最近在搞一个项目所以下班有点晚,坐在地铁上习惯性的拿出Ipad刷一会研究生课程。突然手机响了,一看原来是组织语音会议, 讨论客户需要系统的er图,有400多张要求晚上搞定明天发出去。由于我们没设置外键约束,因此用powerdesigner无法把表之间的关联关系展示出来。由于表数量多、时间紧急,大家讨论说晚上可能时间来不及,建议和用户沟通延后一下。


2、冷静分析

然后我沉默了一会,突然灵感闪现,说把所有的表结构sql给我,到家后看看(没有当场给出答复,毕竟谋定而后动!)


2.1、难点

  • 时间紧急、工作量大;
  • 画关联关系比较复杂,繁琐;

2.2、思维发散

我能找到一些规律吗?是否可以用程序实现?毕竟用计算机能干的工作,就别让人做。

分析sql提取特征

下面给出sql demo

create table `term_relationships`
(
   `object_id`            bigint(20) unsigned not null default 0 comment '对应文章ID/链接ID',
   `term_taxonomy_id`     bigint(20) unsigned not null default 0 comment '对应分类方法ID',
   `term_order`           int(11) not null default 0 comment '排序',
   primary key (`object_id`, `term_taxonomy_id`)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
alter table term_relationships comment '文章属性关系表';
/*==============================================================*/
/* Table: term_taxonomy                                         */
/*==============================================================*/
create table `term_taxonomy`
(
   `term_taxonomy_id`     bigint(20) unsigned not null auto_increment comment 'ID',
   `description`          longtext comment '说明',
   `parent`               bigint(20) unsigned not null default 0 comment '属父分类方法ID',
   `count`                bigint(20) not null default 0 comment '文章数统计',
   `site_id`              bigint(20) comment '站点id',
   primary key (`term_taxonomy_id`)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
alter table term_taxonomy comment '栏目';

经过分析,大部分表外键的命名方式是:被引用表的表名+下划线+id


2.3、解决办法

既然有规律,而且领导意思是准确度可以没那么高,那我就用Python写一个文本解析工具,自动生成外键sql然后再逆向生成er图。


3、方案设计

3.1、数据结构设计

遍历所有行,把表名和键名存储在字典中,数据设计如下:

43.png


其中绿色的是key


3.2、遍历全部sql文本,把表名和主键放在dic里面

处理流程如下


44.png

3.3、再次遍历sql文本,生成外键sql.

处理流程如下


45.png

4、talk is cheap,show me the code

上代码


import math
import re
primayKeyTableMap = {}
class Stack(object):
    def __init__(self):
        self.stack = []
    def push(self, data):
        """
        进栈函数
        """
        self.stack.append(data)
    def pop(self):
        """
        出栈函数,
        """
        return self.stack.pop()
    def gettop(self):
        """
        取栈顶
        """
        return self.stack[-1]
    def __len__(self):
        return len(self.stack)
stack1 =  Stack()
list1 = []
def findTableAndPrimayKey():
    p1 = re.compile(r'[`](.*?)[`]', re.S)
    with open('D:/1.sql','r', encoding='utf-8') as infile:
        for line in infile:
           if 'CREATE TABLE' in line :
                tableName = re.findall(p1, line)[0]
                if len(stack1) != 0 :
                    tempTableKey = stack1.pop()
                    tempTableName = stack1.pop()
                    if len(tempTableKey) > 2:
                        # print(tempTableKey)
                        primayKeyTableMap[tempTableKey] = [tempTableName,tempTableKey]
                    else:
                        # print(tempTableName+'_'+tempTableKey)
                        primayKeyTableMap[removePre(tempTableName)+'_'+tempTableKey] = [tempTableName,tempTableKey]
                stack1.push(tableName)
           if 'PRIMARY KEY' in line :
               keyName = re.findall(p1, line)
               stack1.push(keyName[0])
def addForeignKey():
    tableName = ''
    keyName = ''
    p1 = re.compile(r'[`](.*?)[`]', re.S)
    with open('D:/1.sql','r', encoding='utf-8') as infile:
        for line in infile:
           if 'CREATE TABLE' in line :
                tableName = re.findall(p1, line)[0]
                # stack1.push(tableName)
           elif '_USER_ID' in line or '_user_id' in line:
               foreignCloumn = re.findall(p1, line)
               sql = 'alter table '+tableName+' add foreign key('+foreignCloumn[0]+') references  Z_IS_USER(USER_ID)  on delete cascade on update cascade; '
               print(sql)     
           else :
                foreignCloumn = re.findall(p1, line)
                if len(foreignCloumn) > 0 and  foreignCloumn[0] in primayKeyTableMap and  primayKeyTableMap[foreignCloumn[0]][0]!=tableName :
                    sql = 'alter table '+tableName+' add foreign key('+foreignCloumn[0]+') references '+primayKeyTableMap[foreignCloumn[0]][0]+'('+primayKeyTableMap[foreignCloumn[0]][1]+') on delete cascade on update cascade; '
                    print(sql)
def removePre(tableName):
    return tableName.replace("IS_", "").replace("is_", "").replace("P_", '').replace('QRTZ_','').replace('Z_IS_','').replace('MS_','').replace('acl_','')
def main():
    findTableAndPrimayKey()    
    # print(primayKeyTableMap)
    addForeignKey()
main()

5、总结

  • 本文章利用了python的dic,对应数据结构是map,同时利用了stack存储临时值。
  • 利用了正则来匹配文本
  • 使用了python

6、题外话

敢于打破常规、敢于尝试。

利用程序,2小时我完成了工作,避免了繁琐的画图和加班,哈哈!


相关文章
|
2月前
|
安全 网络安全 Windows
达美航空因大规模IT中断导致数千张机票被取消而起诉CrowdStrike
达美航空因大规模IT中断导致数千张机票被取消而起诉CrowdStrike
考研真题)某银行提供了 1 个服务窗口和 10 个供顾客等待时使用的座位。顾客到达银行时,若有空座位,则到取号机上领取一个号,等待叫号。取号机每次仅允许一位顾客使用。当营业员空闲时,通过叫号选取一位顾
考研真题)某银行提供了 1 个服务窗口和 10 个供顾客等待时使用的座位。顾客到达银行时,若有空座位,则到取号机上领取一个号,等待叫号。取号机每次仅允许一位顾客使用。当营业员空闲时,通过叫号选取一位顾
天梯赛真题——7-6 老板的作息表(25 分)
新浪微博上有人发了某老板的作息时间表,表示其每天 4:30 就起床了。但立刻有眼尖的网友问:这时间表不完整啊,早上九点到下午一点干啥了? 本题就请你编写程序,检查任意一张时间表,找出其中没写出来的时间段。
706 0
天梯赛真题——7-6 老板的作息表(25 分)
|
存储
L2-028 秀恩爱分得快 (25 分)(模拟)
L2-028 秀恩爱分得快 (25 分)(模拟)
207 0
7-17 航空公司VIP客户查询 (10 分)
7-17 航空公司VIP客户查询 (10 分)
180 0
|
定位技术
7-15 城市间紧急救援 (10 分)
7-15 城市间紧急救援 (10 分)
125 0
|
机器学习/深度学习 人工智能 监控
「我的孩子最终没有出生,你们却还在推送育儿广告」
社交网站上的广告能否猜透你的心?广告精准投放真的精准吗?这些算法是否窃取你的隐私和信息,从何窃取?这些广告让你顺心还是伤心?互联网、社交媒体发展以来,人们对数据隐私、广告等一直颇有微词。
113 0
「我的孩子最终没有出生,你们却还在推送育儿广告」
2018春运火车票务系统:每天1500亿浏览量,1秒卖票700张
2018年春节,中国火车票务系统非常牛:每天1500亿浏览量 1秒钟卖票700张。据悉,12306年售票量已超过35亿张的客票,已经成为世界上规模最大的实时票务交易系统。高峰日的网络页面浏览量超过1500亿次,相当于全中国人每人每天访问了票务页面100多次。
10462 0
妈妈们的接种本有用了,输入生产批号就能查到问题疫苗
阿里健康“码上放心”追溯平台,让药品和疫苗各个环节更加透明。
3309 0