You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyODBC批量查询数据库表时脚本中途终止问题排查

脚本遍历数据库表中途随机终止的原因及解决办法

我正在编写一个循环程序,遍历数据库中的29张表,将查询结果存储为DataFrame后写入Excel工作簿。但执行时脚本总会中途停止,停止时机不固定,有时仅执行1次查询,通常执行5-6次后就终止,请问可能的原因是什么?

原代码

import pyodbc
import pandas as pd

conn = pyodbc.connect("DSN=XXXX")
conn.setdecoding(pyodbc.SQL_CHAR, encoding='utf-16-le')
conn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf-16-le')
conn.setencoding(encoding='utf-16-le')
TABLES = ['Table1', 'Table2', ..., 'Table29']

def query_multiple_tables(tables: list[str]) -> list[pd.DataFrame]:
    dataframes = []
    for table in tables:
        QUERY = f"SELECT * FROM [db].[dbo].[{table}]"
        col_crsr = conn.cursor()
        data_crsr = conn.cursor()
        
        cols = [row.column_name for row in col_crsr.columns(table=f"{table}")]
        data = pd.DataFrame.from_records(data_crsr.execute(QUERY).fetchmany(20), columns=cols)
        
        print(f"Extracting table: {table}")
        dataframes.append(data)

        col_crsr.close()
        data_crsr.close()
    
    return dataframes

def write_to_excel(dataframes: list[pd.DataFrame]) -> None:
    
    try:
        with pd.ExcelWriter("Data.xlsx", mode='a', if_sheet_exists='replace') as writer:
            for i, dataframe in enumerate(dataframes):
                dataframe.to_excel(writer, sheet_name=f'{i}')
                print(f"Append successful for: {i}")
    except FileNotFoundError:
        with pd.ExcelWriter("Data.xlsx", mode='w') as writer:
            for i, dataframe in enumerate(dataframes):
                dataframe.to_excel(writer, sheet_name=f'{i}')
                print(f"Initial write successful for: {i}")

data = query_multiple_tables(TABLES)
write_to_excel(data)

可能的原因及修复方案

  • 数据库连接资源耗尽
    每次循环创建两个独立游标,即便调用了close(),pyodbc的游标销毁可能不及时,多次循环后会耗尽连接池资源,导致数据库拒绝新请求。另外全局连接未设置超时,长时间无响应会触发数据库端的连接超时。
    修复:复用单个游标,减少资源创建;给连接添加超时参数(比如timeout=30);脚本结束后主动关闭连接。

  • 未捕获的异常导致脚本崩溃
    循环中的查询、列名获取操作没有异常捕获机制,一旦某张表出现权限问题、表名错误、数据解码失败等情况,脚本会直接终止,表现为“中途停止”。
    修复:在循环内添加try-except块,捕获pyodbc.Error和通用异常,打印错误信息后继续执行后续表的处理。

  • 编码解码错误
    强制设置utf-16-le编码,如果某张表的字段包含该编码无法解析的字符,会触发隐性解码错误,直接终止脚本。
    修复:解码时添加errors='replace'参数忽略错误字符,或尝试改用更通用的utf-8编码。

  • Excel写入阶段的资源冲突
    如果Excel文件被其他程序占用,写入时会触发异常终止脚本;另外mode='a'追加模式在某些版本的pandas中存在兼容性问题。
    修复:确保Excel文件未被打开;写入时也添加异常捕获,避免影响整个流程。

优化后的代码示例

import pyodbc
import pandas as pd

# 添加连接超时,避免长时间无响应
conn = pyodbc.connect("DSN=XXXX", timeout=30)
# 解码时添加错误处理,避免编码问题终止脚本
conn.setdecoding(pyodbc.SQL_CHAR, encoding='utf-16-le', errors='replace')
conn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf-16-le', errors='replace')
conn.setencoding(encoding='utf-16-le')
TABLES = ['Table1', 'Table2', ..., 'Table29']

def query_multiple_tables(tables: list[str]) -> list[pd.DataFrame]:
    dataframes = []
    # 复用单个游标,减少资源开销
    crsr = conn.cursor()
    for table in tables:
        try:
            QUERY = f"SELECT * FROM [db].[dbo].[{table}]"
            # 获取列名
            cols = [row.column_name for row in crsr.columns(table=f"{table}")]
            # 执行查询并读取数据
            crsr.execute(QUERY)
            data = pd.DataFrame.from_records(crsr.fetchmany(20), columns=cols)
            
            print(f"Extracting table: {table}")
            dataframes.append(data)
        except pyodbc.Error as e:
            print(f"数据库操作错误(表{table}): {e}")
        except Exception as e:
            print(f"未知错误(表{table}): {e}")
    # 关闭游标
    crsr.close()
    return dataframes

def write_to_excel(dataframes: list[pd.DataFrame]) -> None:
    try:
        with pd.ExcelWriter("Data.xlsx", mode='a', if_sheet_exists='replace') as writer:
            for idx, dataframe in enumerate(dataframes):
                # 用表名作为sheet名,更直观
                dataframe.to_excel(writer, sheet_name=f'Sheet_{TABLES[idx]}')
                print(f"追加成功: {TABLES[idx]}")
    except FileNotFoundError:
        with pd.ExcelWriter("Data.xlsx", mode='w') as writer:
            for idx, dataframe in enumerate(dataframes):
                dataframe.to_excel(writer, sheet_name=f'Sheet_{TABLES[idx]}')
                print(f"初始写入成功: {TABLES[idx]}")
    except Exception as e:
        print(f"Excel写入错误: {e}")

data = query_multiple_tables(TABLES)
write_to_excel(data)
# 脚本结束后主动关闭连接
conn.close()

内容的提问来源于stack exchange,提问作者Kronivar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 19:42:44