含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
相关产品推荐
相关产品推荐

