數據開發_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+"\r\n" + " ")


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"\n[\s| ]*\n", '', lines)

        # windows的換行是\r\n,unix的是\n,mac的是\r-變成一行的字符串
        # python本身對string長度無強制性限制。使用過程中主要需要考慮電腦性能和程序效率
        # 將文檔變為一行,解決換行引起的問題,這里還可以通過正則的方式,在這里就暫時沒考慮這種實現
        line = sub(' +', ' ', line_text_after.replace('\n', '').replace('\r', '')).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)

以上代碼,簡單的實現了目前的需求,后續將這部分做成工具,可以方便后續的使用。結合其他文件處理工具,可以更好的處理各種情況

參考

 參考了部分正則表達式的語法等數據


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM