• 数据开发_Python解析sql提取表


    基于Python实现解析SQL代码中的表

    1.问题:
     有一批SQL代码,需要提取其中用到的表。
    2.实现思路:
      01.通过正则匹配的方式,将sql分为三类 create from|join insert的这几种情况
      02. 使用脚本语言Python开发,快捷
    3.注意事项
      01.前提假设: 
      SQL都是规范的可运行的。 schema.table_name 的形式或者 table_name的形式,
      如果schema 和 table_name之间有多个空格的情况,这种要特殊处理一下
      test_a. my_table_nm 这种情况会把只提取出 test_a. 的形式,针对这种情况,可以采用以下方式
      处理例如:  line = sub(r"test_a. ", r'test_a.', line)
      02. 注释的代码不需要
    

    代码实现

    代码中内容,只是日常处理数据使用,没有考虑正式生产环境,比如没有日志记录等部件。如果要到生产环境,要做的工作还不少。
     在日常中使用,如果要用多次的话,还是写成工具的形式
    
    #!/usr/bin/env python
    # -*-coding:utf-8-*-
    # @file extract_sql_table.py
    
    from re import match,  sub, compile
    import os
    import pandas as pd
    
    
    def extract_pure_field(sql_file_name, res_file):
        """去除多余空格,空行, 注释 配置 等"""
        # 后缀换成 txt
        with open(sql_file_name, mode='r', encoding='utf8') as fileObj, 
                open(res_file, mode='w', encoding='utf8') as f2:
            for line, data in enumerate(fileObj):
                # .strip() 去除字符串首尾的空格
                line_text = data.strip().lower()
                # 有 insert 的行<默认insert 紧跟着表且在同一行>
                if match('^--.*|^set .*', line_text) is  None:
                    # 多个空格变为一个空格
                    line_text_after = sub(' +', ' ', line_text)
                    print("行数 ", line, sep=',')
                    f2.writelines(line_text_after+"
    " + " ")
    
    
    def extract_table_name(sql_file_name, extract_flag='3'):
        """提取from 或者 join后面的 Table
        extract_flag='1'  overwrite|into 后的表名
        extract_flag='2'  create         后的表名
        extract_flag='3'  from|join        的表名
        """
        with open(sql_file_name, mode='r', encoding='utf-8') as fileObj:
            job_file = os.path.split(os.path.splitext(sql_file_name)[0])[1]
            # read() 每次读取整个文件,它通常用于将文件内容放到一个字符串变量中
            lines = fileObj.read()
    
            # 删除空行
            line_text_after = sub(r"
    [s| ]*
    ", '', lines)
    
            # windows的换行是
    ,unix的是
    ,mac的是
    -变成一行的字符串
            # python本身对string长度无强制性限制。使用过程中主要需要考虑电脑性能和程序效率
            # 将文档变为一行,解决换行引起的问题,这里还可以通过正则的方式,在这里就暂时没考虑这种实现
            line = sub(' +', ' ', line_text_after.replace('
    ', '').replace('
    ', '')).lower()
            # 部分表名不规范 text. Test_D_history 多出了个空格,这种情况处理需额外添加条件处理
    
            # 数字、26个英文字母或者下划线 和 英文句号组成的字符串,这部分的正则表达式可以再了解了解
            if extract_flag == '1':
                pattern_tuple = compile('insert (?:overwrite table|into table|overwrite|into) [0-9a-zA-Z_\.]{1,}')
                pattern_string = "overwrite|into"
                table_location = -1
            elif extract_flag == '2':
                pattern_tuple = compile('create (?:table if not exists|table) [0-9a-zA-Z_\.]{1,}')
                pattern_string = "create"
                table_location = -1
            else:
                pattern_tuple = compile('(?:from|join) [0-9a-zA-Z_\.]{1,}.*?')
                pattern_string = 'from|join'
                table_location = 1
    
            # 表名提取
            # 存储结果
            table_list = []
            data_tuple = pattern_tuple.findall(line)
            for table in data_tuple:
                table_name = table.split(" ")[table_location]
                comb_job_table_data = job_file, pattern_string, table_name
                print(comb_job_table_data)
                table_list.append(comb_job_table_data)
            return table_list
    
    
    if __name__ == '__main__':
        infile_name = r"C:/Users/Desktop/test.sql"
        out_put_file = r"C:/Users/Desktop/select_table_nm.txt"
        res_file = os.path.splitext(infile_name)[0] + '.txt'
    
        # 处理文件注释等情况
        extract_pure_field(infile_name, res_file)
        # 提取表  1 是 overwrite|into表, 2是create 其余情况是 from|join
        table_job_list = extract_table_name(res_file, "3")
        # 将表写到数据框
        result_data = pd.DataFrame(table_job_list).drop_duplicates()
        # 追加的形式写入
        result_data.to_csv(path_or_buf=out_put_file, mode='a', index=False, header=False)
        # 移除中间文件
        #os.remove(res_file)
    
    
    以上代码,简单的实现了目前的需求,后续将这部分做成工具,可以方便后续的使用。结合其他文件处理工具,可以更好的处理各种情况
    

    参考

     参考了部分正则表达式的语法等数据
  • 相关阅读:
    用Springboot写一个只有一个条件的复杂查询
    Springboot The requested profile "pom.xml" could not be activated because it doesn't not exists
    springboot配置路径
    vuex
    @MappedSuperclass的作用
    icon.css
    default.html
    WebService调用
    通用分页存储过程
    存储过程获得最新订单号
  • 原文地址:https://www.cnblogs.com/ytwang/p/13748903.html
Copyright © 2020-2023  润新知