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

含Python脚本的SSIS包无法在SQL Server代理作业中运行

SQL Server代理作业执行Python脚本失败(手动运行正常)排查与解决

问题概述

实现数据流程:通过Python脚本抓取Yahoo Finance指定股票数据并存储到SQL Server,封装为SSIS包后加入SQL Server代理作业实现批量自动加载。异常现象:脚本在命令行、Visual Studio、SSMS手动执行均成功,但作为SQL Server代理作业步骤运行时出错。已为SQLSERVERAGENT用户添加Python文件所在文件夹权限,问题仍未解决。

附Python代码:

import pandas as pd
import yfinance as yf
from sqlalchemy import create_engine
import sqlalchemy
from datetime import datetime

servername = "XXXXXXX"
dbname = "sql_prtfl_dw"
table = "lz_yahoo_finance_stock_prices"

engine = create_engine("mssql+pyodbc://@"+ servername + "/"+ dbname + "?trusted_connection=yes&driver=ODBC+Driver+17+for+SQL+Server")
conn = engine.connect()

TickerSymbols = pd.read_sql(
    """
    SELECT 
        Ticker
    FROM DimAssets
    WHERE 1=1
        AND AssetClass IN ('Equities')
        AND IsCurrent = 1
    """
    , engine)

conn.invalidate()
engine.dispose()

TickerSymbols = TickerSymbols["Ticker"].values.tolist()

servername = "XXXXXXX"
dbname = "sql_prtfl_lz"
table = "lz_yahoo_finance_stock_prices"

engine = create_engine("mssql+pyodbc://@"+ servername + "/"+ dbname + "?trusted_connection=yes&driver=ODBC+Driver+17+for+SQL+Server")
conn = engine.connect()

def sql_importer(symbol, table=table, start="2019-01-01"): 
    try: 
        max_date = pd.to_datetime(pd.read_sql(f"SELECT MAX(Date) FROM [{table}] WHERE Ticker IN ('{symbol}')", engine).values[0][0])
        print(max_date)
        new_data = yf.download(symbol, start=max_date)
        new_data.insert(0, "Ticker", symbol)
        new_data.insert(7, "EtlLoadDate", datetime.now())
        new_rows = new_data[new_data.index > max_date]
        new_rows.to_sql(table, engine, if_exists="append")
        print(f"Ticker: {symbol} - {str(len(new_rows))} extra rows imported in table: {table}")
    except: 
        new_data = yf.download(symbol, start=start)
        new_data.insert(0, "Ticker", symbol)
        new_data.insert(7, "EtlLoadDate", datetime.now())
        new_data.to_sql(table, engine, if_exists="append")
        print(f"Ticker: {symbol} - First time import of data. {str(len(new_data))} new datarows are imported in table: {table}")
        
for ticker in TickerSymbols: 
    sql_importer(ticker)
    
conn.invalidate()
engine.dispose()

排查方向与解决方法

1. 数据库权限不足

脚本使用trusted_connection=yes(Windows身份验证),此时SQL Server代理服务账户(默认NT SERVICE\SQLSERVERAGENT)需具备:

  • 对sql_prtfl_dw库DimAssets表的SELECT权限
  • 对sql_prtfl_lz库lz_yahoo_finance_stock_prices表的SELECT、INSERT权限
    解决:在SSMS中为NT SERVICE\SQLSERVERAGENT在两个数据库中创建用户,并分配对应权限。

2. Python环境与依赖差异

手动运行用当前用户的Python环境,SQL代理用服务账户环境,可能存在:

  • Python路径未配置:代理账户PATH中无Python安装路径,需在作业步骤中指定Python绝对路径(如C:\Python39\python.exe)执行脚本
  • 依赖包缺失:手动安装的yfinance/pandas/sqlalchemy等包仅在当前用户环境,需以管理员身份执行pip install yfinance pandas sqlalchemy pyodbc安装到全局环境,或指定虚拟环境的Python路径

3. ODBC驱动访问权限

脚本依赖ODBC Driver 17 for SQL Server,需确认NT SERVICE\SQLSERVERAGENT对驱动安装目录(默认C:\Windows\System32)有读取权限。

4. 网络访问限制

Yahoo Finance API需外网访问,代理账户可能受防火墙/代理限制:

  • 检查服务器防火墙,允许NT SERVICE\SQLSERVERAGENT访问finance.yahoo.com等相关域名
  • 若服务器需代理,为服务账户配置代理参数

5. 异常捕获掩盖错误

现有try-except未输出具体异常,无法定位问题。修改脚本添加异常详情:

def sql_importer(symbol, table=table, start="2019-01-01"): 
    try: 
        # 原有代码逻辑
    except Exception as e: 
        print(f"Ticker: {symbol} - 错误详情: {str(e)}")
        # 原有异常处理逻辑

同时在代理作业步骤中勾选「输出到文件」,指定可写入的日志路径,查看具体错误信息。

6. SSIS包执行权限

若通过SSIS包调用脚本,需确认:

  • 代理账户对SSIS包所在路径有读取权限
  • SSIS服务运行账户具备数据库与文件访问权限

快速验证方法

用PsExec工具模拟代理账户环境执行脚本:

psexec -s -i cmd.exe

在弹出的命令行中执行Python脚本,直接复现代理账户的运行环境,快速定位问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 13:43:31