Sql脚本分析工具

查看 50|回复 9
作者:phantomxjc   
针对于Sql建库脚本语句,用于分析其建库表的字段,
使用方法:导出数据库结构sql,然后开始转换即可
[Asm] 纯文本查看 复制代码import re
from docx import Document
from docx.shared import Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext, ttk
import threading
import os
import sys
from datetime import datetime
class SQLToWordConverter:
    def __init__(self, root):
        self.root = root
        self.root.title("SQL到Word文档转换器")
        self.root.geometry("700x550")
        self.root.resizable(False, False)
        self.root.configure(bg="#f0f0f0")
        # 设置图标(如果有)
        try:
            self.root.iconbitmap("database.ico")  # 如果有图标文件的话
        except:
            pass
        # 文件路径变量
        self.sql_file_path = tk.StringVar()
        self.output_file_path = tk.StringVar()
        self.create_widgets()
    def create_widgets(self):
        # 标题框架
        title_frame = tk.Frame(self.root, bg="#2c3e50", height=80)
        title_frame.pack(fill=tk.X)
        title_frame.pack_propagate(False)
        title_label = tk.Label(title_frame, text="SQL到Word文档转换器",
                               font=("Arial", 16, "bold"), fg="white", bg="#2c3e50")
        title_label.pack(pady=20)
        # 主内容框架
        main_frame = tk.Frame(self.root, bg="#f0f0f0", padx=20, pady=20)
        main_frame.pack(fill=tk.BOTH, expand=True)
        # SQL文件选择
        sql_frame = tk.Frame(main_frame, bg="#f0f0f0")
        sql_frame.pack(fill=tk.X, pady=10)
        tk.Label(sql_frame, text="SQL文件:", font=("Arial", 10),
                 bg="#f0f0f0").grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
        sql_entry = tk.Entry(sql_frame, textvariable=self.sql_file_path,
                             width=50, font=("Arial", 10))
        sql_entry.grid(row=0, column=1, padx=5, sticky=tk.EW)
        sql_btn = tk.Button(sql_frame, text="浏览", command=self.browse_sql_file,
                            bg="#3498db", fg="white", font=("Arial", 10), relief=tk.FLAT)
        sql_btn.grid(row=0, column=2, padx=(5, 0))
        sql_frame.columnconfigure(1, weight=1)
        # 输出文件选择
        output_frame = tk.Frame(main_frame, bg="#f0f0f0")
        output_frame.pack(fill=tk.X, pady=10)
        tk.Label(output_frame, text="输出文件:", font=("Arial", 10),
                 bg="#f0f0f0").grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
        output_entry = tk.Entry(output_frame, textvariable=self.output_file_path,
                                width=50, font=("Arial", 10))
        output_entry.grid(row=0, column=1, padx=5, sticky=tk.EW)
        output_btn = tk.Button(output_frame, text="浏览", command=self.browse_output_file,
                               bg="#3498db", fg="white", font=("Arial", 10), relief=tk.FLAT)
        output_btn.grid(row=0, column=2, padx=(5, 0))
        output_frame.columnconfigure(1, weight=1)
        # 按钮框架
        button_frame = tk.Frame(main_frame, bg="#f0f0f0")
        button_frame.pack(pady=20)
        convert_btn = tk.Button(button_frame, text="开始转换", command=self.start_conversion,
                                bg="#2ecc71", fg="white", font=("Arial", 12, "bold"),
                                width=15, height=2, relief=tk.FLAT)
        convert_btn.pack(pady=5)
        # 日志区域
        log_frame = tk.LabelFrame(main_frame, text="日志输出", font=("Arial", 10, "bold"),
                                  bg="#f0f0f0", fg="#2c3e50")
        log_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        self.log_text = scrolledtext.ScrolledText(log_frame, height=12, wrap=tk.WORD,
                                                  font=("Consolas", 9))
        self.log_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        # 状态栏
        status_frame = tk.Frame(self.root, bg="#ecf0f1", height=30)
        status_frame.pack(fill=tk.X)
        status_frame.pack_propagate(False)
        self.status_label = tk.Label(status_frame, text="就绪", font=("Arial", 9),
                                     bg="#ecf0f1", fg="#7f8c8d")
        self.status_label.pack(side=tk.LEFT, padx=10)
        # 版权信息
        copyright_label = tk.Label(status_frame,
                                   text="© 2023 SQL转换工具",
                                   font=("Arial", 9), bg="#ecf0f1", fg="#7f8c8d")
        copyright_label.pack(side=tk.RIGHT, padx=10)
    def browse_sql_file(self):
        file_path = filedialog.askopenfilename(
            title="选择SQL文件",
            filetypes=[("SQL文件", "*.sql"), ("所有文件", "*.*")]
        )
        if file_path:
            self.sql_file_path.set(file_path)
            # 自动生成输出文件路径
            if not self.output_file_path.get():
                base_name = os.path.splitext(os.path.basename(file_path))[0]
                output_path = os.path.join(os.path.dirname(file_path), f"{base_name}_文档.docx")
                self.output_file_path.set(output_path)
    def browse_output_file(self):
        file_path = filedialog.asksaveasfilename(
            title="保存Word文档",
            defaultextension=".docx",
            filetypes=[("Word文档", "*.docx"), ("所有文件", "*.*")]
        )
        if file_path:
            self.output_file_path.set(file_path)
    def log_message(self, message):
        timestamp = datetime.now().strftime("%H:%M:%S")
        self.log_text.insert(tk.END, f"[{timestamp}] {message}\n")
        self.log_text.see(tk.END)
        self.root.update_idletasks()
    def start_conversion(self):
        sql_path = self.sql_file_path.get()
        output_path = self.output_file_path.get()
        if not sql_path:
            messagebox.showerror("错误", "请选择SQL文件")
            return
        if not output_path:
            messagebox.showerror("错误", "请选择输出文件路径")
            return
        # 清空日志
        self.log_text.delete(1.0, tk.END)
        self.status_label.config(text="正在处理...")
        # 在新线程中执行转换,避免界面冻结
        thread = threading.Thread(target=self.convert, args=(sql_path, output_path))
        thread.daemon = True
        thread.start()
    def convert(self, sql_path, output_path):
        try:
            self.log_message("正在解析SQL文件...")
            tables = parse_sql_file(sql_path)
            self.log_message(f"成功解析 {len(tables)} 个表")
            self.log_message("正在生成Word文档...")
            create_word_document(tables, output_path)
            self.log_message(f"文档已保存到: {output_path}")
            self.log_message("处理完成!")
            self.status_label.config(text="转换完成")
            messagebox.showinfo("成功", "转换完成!")
        except Exception as e:
            error_msg = f"处理过程中出现错误: {str(e)}"
            self.log_message(error_msg)
            self.status_label.config(text="转换失败")
            messagebox.showerror("错误", error_msg)
def parse_sql_file(file_path):
    """
    解析SQL文件,提取表结构和字段信息
    """
    with open(file_path, 'r', encoding='utf-8') as f:
        content = f.read()
    # 移除注释和多余空格,便于处理
    content = re.sub(r'--.*?$', '', content, flags=re.MULTILINE)  # 移除行注释
    content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)  # 移除块注释
    content = re.sub(r'\n+', '\n', content)  # 移除多余空行
    # 查找所有CREATE TABLE语句
    table_pattern = r'CREATE TABLE (?:IF NOT EXISTS )?`?(.*?)`?\s*\((.*?)\)\s*[^)]*?;'
    table_blocks = re.findall(table_pattern, content, re.DOTALL | re.IGNORECASE)
    tables = []
    for table_name, table_body in table_blocks:
        # 处理表名
        table_name = table_name.strip().replace('`', '')
        # 解析表体内的字段定义
        lines = [line.strip() for line in table_body.split('\n') if line.strip()]
        fields = []
        field_index = 1
        for line in lines:
            # 跳过约束和索引行
            if (line.startswith('PRIMARY KEY') or line.startswith('KEY') or
                    line.startswith('UNIQUE KEY') or line.startswith('CONSTRAINT') or
                    line.startswith('FOREIGN KEY')):
                continue
            # 提取字段基本信息
            field_match = re.match(r'`?([^`\s]+)`?\s+([a-zA-Z]+)(?:\(([^)]+)\))?', line)
            if field_match:
                field_name = field_match.group(1)
                field_type = field_match.group(2).upper()
                field_domain = field_match.group(3) if field_match.group(3) else ''
                # 专门提取注释内容 - 位于COMMENT之后,单引号包裹,以逗号结束
                comment_match = re.search(r"COMMENT\s+'([^']+)',?", line, re.IGNORECASE)
                field_comment = comment_match.group(1) if comment_match else ''
                fields.append({
                    'index': field_index,
                    'name': field_name,
                    'type': field_type,
                    'domain': field_domain,
                    'comment': field_comment
                })
                field_index += 1
        tables.append({
            'name': table_name,
            'fields': fields
        })
    return tables
def create_word_document(tables, output_path):
    """
    创建Word文档并填充表结构信息
    """
    doc = Document()
    # 设置文档标题
    title = doc.add_heading('数据库表结构文档', 0)
    title.alignment = WD_ALIGN_PARAGRAPH.CENTER
    # 添加每个表的信息
    for table in tables:
        # 添加表名标题
        heading = doc.add_heading(f'表: {table["name"]}', level=1)
        # 创建表格
        table_grid = doc.add_table(rows=1, cols=5)
        table_grid.style = 'Table Grid'
        # 设置表格列宽
        col_widths = [0.5, 1.5, 1.5, 1.5, 3.0]  # 单位英寸
        for i, width in enumerate(col_widths):
            for cell in table_grid.columns.cells:
                cell.width = Inches(width)
        # 设置表头
        hdr_cells = table_grid.rows[0].cells
        headers = ['序号', '字段代码', '字段类型', '值域', '注释']
        for i, header in enumerate(headers):
            hdr_cells.text = header
            hdr_cells.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
            hdr_cells.paragraphs[0].runs[0].bold = True
        # 填充数据行
        for field in table['fields']:
            row_cells = table_grid.add_row().cells
            row_cells[0].text = str(field['index'])
            row_cells[1].text = field['name']
            row_cells[2].text = field['type']
            row_cells[3].text = field['domain']
            row_cells[4].text = field['comment']
            # 设置单元格对齐方式
            row_cells[0].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
            for i in range(1, 5):
                row_cells.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.LEFT
        # 在表之间添加空行
        doc.add_paragraph()
    # 保存文档
    doc.save(output_path)
def main():
    root = tk.Tk()
    app = SQLToWordConverter(root)
    root.mainloop()
if __name__ == "__main__":
    main()



sql语句如下所示:
[Asm] 纯文本查看 复制代码-- 创建数据库(如果不存在)
CREATE DATABASE IF NOT EXISTS example_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE example_db;
-- 用户表
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY COMMENT '用户ID',
    username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
    email VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱',
    password_hash VARCHAR(255) NOT NULL COMMENT '加密密码',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) COMMENT='用户表';
-- 商品表
CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '商品ID',
    name VARCHAR(100) NOT NULL COMMENT '商品名称',
    description TEXT COMMENT '商品描述',
    price DECIMAL(10, 2) NOT NULL COMMENT '商品价格',
    stock INT DEFAULT 0 COMMENT '库存数量',
    status ENUM('AVAILABLE', 'DISCONTINUED') DEFAULT 'AVAILABLE' COMMENT '商品状态',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) COMMENT='商品表';
-- 订单表
CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '订单ID',
    user_id INT NOT NULL COMMENT '用户ID',
    total_amount DECIMAL(10, 2) NOT NULL COMMENT '订单总金额',
    status ENUM('PENDING', 'PAID', 'SHIPPED', 'COMPLETED', 'CANCELLED') DEFAULT 'PENDING' COMMENT '订单状态',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) COMMENT='订单表';
-- 订单明细表
CREATE TABLE order_items (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '明细ID',
    order_id INT NOT NULL COMMENT '订单ID',
    product_id INT NOT NULL COMMENT '商品ID',
    quantity INT NOT NULL COMMENT '购买数量',
    unit_price DECIMAL(10, 2) NOT NULL COMMENT '商品单价',
    subtotal DECIMAL(10, 2) NOT NULL COMMENT '小计金额',
    FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
    FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
) COMMENT='订单明细表';
生成结果文件如下:



文件, 文档

sos218909   

改个名字吧,《数据库字段文档生成工具》
yzqdev   

这个sql分析工具好啊,可以帮自己省下很多时间啊,谢谢大佬!
yaoyi   

如果能换下就更好了,根据表格,转换成sql脚本
phantomxjc
OP
  


yaoyi 发表于 2025-8-26 15:44
如果能换下就更好了,根据表格,转换成sql脚本

那对文档要求就特别高了
chendaihua   

是某个库的所有表吗,那有的数据库多的咱办。能单独指定吗
jimhuhu   

棒  哈哈  学习学习
xiaoshengzi   

数据库表结构 文档生成工具
wu20080808   

怎们看着像数据库的表结构来着
phantomxjc
OP
  


wu20080808 发表于 2025-8-26 17:13
怎们看着像数据库的表结构来着

就是分析数据库的表结构
您需要登录后才可以回帖 登录 | 立即注册