Oracle数据库表结构导出脚本

table_to_csv.py

import cx_Oracle
import csv
import os
from datetime import datetime
cx_Oracle.init_oracle_client(lib_dir=r'D:\oracleclient\instantclient_23_8')

def export_oracle_query_to_csv(sql, output_file=None):
    # 默认数据库配置
    db_config = {
        'user': 'system',
        'password': 'xxxxx',
        'dsn': '10.12.8.55:1521/gemesdb',
        'encoding': 'UTF-8'
    }
    

    # 如果未指定输出文件,生成默认文件名
    if not output_file:
        # 生成带时间戳的文件名
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        output_file = f"table_structrue_{timestamp}.csv"
    
    try:
        # 建立数据库连接
        with cx_Oracle.connect(**db_config) as connection:
            # 创建游标
            with connection.cursor() as cursor:
                # 执行SQL查询
                cursor.execute(sql)
                
                # 获取列名
                column_names = [desc[0] for desc in cursor.description]
                
                # 写入CSV文件
                with open(output_file, 'w', newline='', encoding='utf-8-sig') as csvfile:
                    writer = csv.writer(csvfile)
                    
                    # 写入表头
                    writer.writerow(column_names)
                    
                    # 分批写入数据,避免内存溢出
                    batch_size = 1000
                    while True:
                        rows = cursor.fetchmany(batch_size)
                        if not rows:
                            break
                        writer.writerows(rows)
        
        print(f"数据已成功导出到 {os.path.abspath(output_file)}")
        return output_file
        
    except Exception as e:
        print(f"导出过程发生错误: {str(e)}")
        raise    


# 定义SQL查询
sql =  """
      SELECT 
        tc.owner,
        tc.table_name,
        '' as tcomments,
        cc.column_name,
        cols.data_type,
        NVL(cols.data_length, 0) as data_length,
        NVL(cols.data_precision, 0) as  data_precision,
        NVL(cols.data_scale, 0) as data_scale,
        cols.nullable,
        cols.data_default,
        '' as ccomments
    FROM 
        all_tab_comments tc
    JOIN 
        all_col_comments cc 
        ON tc.table_name = cc.table_name 
        AND tc.owner = cc.owner
    JOIN 
        all_tab_columns cols 
        ON cc.table_name = cols.table_name 
        AND cc.column_name = cols.column_name 
        AND cc.owner = cols.owner
    WHERE 
        tc.owner IN  ('MES_PROD','DCS_PROD','DFS_PROD','MES_REPORT_PROD','RMS_PROD','GOERTEK','SF_SECURITY','SF_AMC','SF_QUARTY') 
        and cc.comments is null 
    ORDER BY 
        tc.owner,
        tc.table_name, 
        cols.column_id
    """

# 导出数据到CSV

export_oracle_query_to_csv(
    sql=sql
)


  # ('MES_PROD','DCS_PROD','DFS_PROD','MES_REPORT_PROD','RMS_PROD','GOERTEK','SF_SECURITY','SF_AMC','SF_QUARTY') 
    
   # ('EDAPROD','PMS_CORE','PMS_PORTAL','PMS_SEATA','PMS_SYSTEM','PMS_USER','RPT_DW','RPT_DW_READ','RPT_ODS','SPC_PROD') 

table_to_html.py

import cx_Oracle
import json
import sys
from datetime import datetime
from jinja2 import Environment, FileSystemLoader
import os

# 设置环境变量(根据数据库字符集调整)
cx_Oracle.init_oracle_client(lib_dir=r'D:\oracleclient\instantclient_23_8')
def query_to_html(config, sql_query, template_file, output_file, dbname):
  
    try:
        # 建立数据库连接
        connection = cx_Oracle.connect(
            user=config['username'],
            password=config['password'],
            dsn=config['dsn']
        )
        print(f"成功连接到数据库: {connection.version}")
        
        # 创建游标并执行查询
        cursor = connection.cursor()
        cursor.execute(sql_query)
        
        # 获取列名
        columns = [desc[0] for desc in cursor.description]
        
        # 使用defaultdict组织数据
        users_data = {}
        
        # 处理查询结果
        for row in cursor:
            row_data = dict(zip(columns, row))
            
            # 提取用户信息
            owner = row_data['OWNER']
            
            # 提取表信息
            table_name = row_data['TABLE_NAME']
            tcomments = row_data['TCOMMENTS']
            
            # 提取列信息
            column_info = {
                "name": row_data['COLUMN_NAME'],
                "data_type": row_data['DATA_TYPE'],
                "length": row_data['DATA_LENGTH'] if row_data['DATA_LENGTH'] != 0 else None,
                "precision": row_data['DATA_PRECISION'] if row_data['DATA_PRECISION'] != 0 else None,
                "scale": row_data['DATA_SCALE'] if row_data['DATA_SCALE'] != 0 else None,
                "nullable": row_data['NULLABLE'],
                "default_value": row_data['DATA_DEFAULT'],
                "comment": row_data['CCOMMENTS']
            }
            
            # 初始化用户数据结构
            if owner not in users_data:
                users_data[owner] = {
                    "username": owner,
                    "usertable_count": 0,
                    "tables": {}
                }
            
            # 初始化表数据结构
            if table_name not in users_data[owner]['tables']:
                users_data[owner]['tables'][table_name] = {
                    "name": table_name,
                    "comment": tcomments,
                    "columns": []
                }
                users_data[owner]['usertable_count'] += 1
            
            # 添加列信息
            users_data[owner]['tables'][table_name]['columns'].append(column_info)
        
        # 将表数据转换为列表形式
        for user in users_data.values():
            user['tables'] = list(user['tables'].values())
        
        # 准备渲染数据
        render_data = {
            "dbname": dbname,
            "user_count": len(users_data),
            "table_count": sum(user['usertable_count'] for user in users_data.values()),
            "generate_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "users": list(users_data.values())
        }
        
        # 初始化Jinja2环境
        env = Environment(loader=FileSystemLoader('.'))
        template = env.get_template(template_file)
        
        # 渲染HTML
        rendered_html = template.render(render_data)
        
        # 保存为HTML文件
       
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write(rendered_html)
        
        print(f"数据已成功导出到: {output_file}")
        
    except cx_Oracle.Error as error:
        print(f"数据库错误: {error}")
    except Exception as e:
        print(f"发生错误: {e}")
    finally:
        # 关闭数据库连接
        if 'connection' in locals():
            connection.close()
            print("数据库连接已关闭")

if __name__ == "__main__":
    # 数据库连接配置
    config = {
        "username": "system",
        "password": "Zeta@xxxx#$",
        "dsn": "10.12.8.61:1521/edadb"
    }
    
# z9m_T2W6
# 10.12.8.55:1521/gemesdb


    # SQL查询语句
    sql_query = """
     SELECT 
        tc.owner,
        tc.table_name,
        tc.comments as tcomments,
        cc.column_name,
        cols.data_type,
        NVL(cols.data_length, 0) as data_length,
        NVL(cols.data_precision, 0) as  data_precision,
        NVL(cols.data_scale, 0) as data_scale,
        cols.nullable,
        cols.data_default,
        replace(replace (replace (cc.comments,',',','),chr(10),'|'),chr(13),'|') as ccomments
    FROM 
        all_tab_comments tc
    JOIN 
        all_col_comments cc 
        ON tc.table_name = cc.table_name 
        AND tc.owner = cc.owner
    JOIN 
        all_tab_columns cols 
        ON cc.table_name = cols.table_name 
        AND cc.column_name = cols.column_name 
        AND cc.owner = cols.owner
    WHERE 
        tc.owner IN       ('SPC_PROD') 
    ORDER BY 
        tc.owner,
        tc.table_name, 
        cols.column_id
    """
    
    # 模板文件和输出文件
    template_file = "table_template.html"  # 确保此文件存在
    output_file = "SPC_PROD_table_structure.html"
    
    # 执行查询并生成HTML
    query_to_html(config, sql_query, template_file, output_file,dbname="edadb")


 
   # ('MES_PROD','DCS_PROD','DFS_PROD','MES_REPORT_PROD','RMS_PROD','GOERTEK','SF_SECURITY','SF_AMC','SF_QUARTY') 
    
   # ('EDAPROD','PMS_CORE','PMS_PORTAL','PMS_SEATA','PMS_SYSTEM','PMS_USER','RPT_DW','RPT_DW_READ','RPT_ODS','SPC_PROD') 

table_template.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ dbname }}数据库表结构</title>
    <style>
        body {
            font-family: 'Helvetica Neue', Arial, sans-serif;
            line-height: 1.6;
            color: #333;
            background-color: #f9f9f9;
            margin: 0;
            padding: 20px;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
        }

        .user-module {
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 2px 12px rgba(0,0,0,0.08);
            margin-bottom: 30px;
            overflow: hidden;
        }

        .user-header {
            background-color: #4a6fa5;
            color: white;
            padding: 15px 20px;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .user-header h2 {
            margin: 0;
            font-size: 1.5em;
        }

        .user-content {
            padding: 20px;
        }

        .table-section {
            margin-bottom: 20px;
            border: 1px solid #e8e8e8;
            border-radius: 4px;
        }

        .table-header {
            background-color: #f8f8f8;
            padding: 12px 15px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .table-title {
            display: flex;
            align-items: center;
        }

        .table-name {
            font-size: 1.1em;
            font-weight: 500;
        }

        .table-comment {
            color: #666;
            font-style: italic;
            margin-left: 12px;
        }

        .table-expand-btn {
            background-color: #f0f0f0;
            border: none;
            padding: 6px 10px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 0.9em;
            transition: background-color 0.3s;
        }

        .table-expand-btn:hover {
            background-color: #e0e0e0;
        }

        .field-table {
            width: 100%;
            border-collapse: collapse;
            font-size: 0.95em;
            display: none; /* 默认折叠 */
        }

        .field-table th, .field-table td {
            padding: 10px 12px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .field-table th {
            background-color: #f0f0f0;
            font-weight: 600;
        }

        .field-table tr:nth-child(even) {
            background-color: #f8f8f8;
        }

        .nullable-yes {
            color: #008000;
        }

        .nullable-no {
            color: #cc0000;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1 class="text-center mb-4">{{ dbname }}数据库表结构 用户数量:{{ user_count }}表数量: {{ table_count }}</h1>
        <p class="text-center text-gray-600 mb-6">生成时间: {{ generate_time }}</p>

        {% for user in users %}
        <div class="user-module">
            <div class="user-header" onclick="toggleUserContent('{{ user.username }}')">
                <h2>用户: {{ user.username }}     表数量:{{ user.usertable_count }}</h2>
                <button class="expand-btn" id="{{ user.username }}_btn">展开</button>
            </div>
            <div class="user-content" id="{{ user.username }}_content">
                {% for table in user.tables %}
                <div class="table-section">
                    <div class="table-header" onclick="toggleTableContent('{{ user.username }}', '{{ table.name }}')">
                        <div class="table-title">
                            <span class="table-name">{{ table.name }}</span>
                            {% if table.comment %}
                            <span class="table-comment">---- {{ table.comment }}</span>
                            {% endif %}
                        </div>
                        <button class="table-expand-btn" id="{{ user.username }}_{{ table.name }}_btn">展开</button>
                    </div>
                    <table class="field-table" id="{{ user.username }}_{{ table.name }}_content">
                        <thead>
                            <tr>
                                <th>字段名</th>
                                <th>数据类型</th>
                                <th>长度</th>
                                <th>精度</th>
                                <th>刻度</th>
                                <th>是否可为空</th>
                                <th>默认值</th>
                                <th>字段注释</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for column in table.columns %}
                            <tr>
                                <td>{{ column.name }}</td>
                                <td>{{ column.data_type }}</td>
                                <td>{{ column.length|default('-') }}</td>
                                <td>{{ column.precision|default('-') }}</td>
                                <td>{{ column.scale|default('-') }}</td>
                                <td class="{{ 'nullable-yes' if column.nullable == 'Y' else 'nullable-no' }}">
                                    {{ '是' if column.nullable == 'Y' else '否' }}
                                </td>
                                <td>{{ column.default_value|default('-') }}</td>
                                <td>{{ column.comment|default('-') }}</td>
                            </tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
                {% endfor %}
            </div>
        </div>
        {% endfor %}

        <script>
            function toggleUserContent(username) {
                const content = document.getElementById(`${username}_content`);
                const btn = document.getElementById(`${username}_btn`);
                
                if (content.style.display === 'none') {
                    content.style.display = 'block';
                    btn.textContent = '收起';
                } else {
                    content.style.display = 'none';
                    btn.textContent = '展开';
                }
            }

            function toggleTableContent(username, tableName) {
                const content = document.getElementById(`${username}_${tableName}_content`);
                const btn = document.getElementById(`${username}_${tableName}_btn`);
                
                if (content.style.display === 'none') {
                    content.style.display = 'table'; // 显示表格
                    btn.textContent = '收起';
                } else {
                    content.style.display = 'none';
                    btn.textContent = '展开';
                }
            }

            // 默认折叠所有表结构(用户模块默认折叠)
            document.addEventListener('DOMContentLoaded', function() {
                // 折叠所有用户内容
                document.querySelectorAll('.user-content').forEach(content => {
                    content.style.display = 'none';
                });
                
                // 折叠所有表内容
                document.querySelectorAll('.field-table').forEach(table => {
                    table.style.display = 'none';
                });
                
                // 设置表按钮文本为"展开"
                document.querySelectorAll('.table-expand-btn').forEach(btn => {
                    btn.textContent = '展开';
                });
            });
        </script>
    </div>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为什么不问问神奇的海螺呢丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值