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

Python操作MSSQL时同一列表两次作为IN参数传参报错解决

问题根因

pyodbc的参数化查询严格按?占位符的顺序一一匹配入参,你写的SQL里两个IN子句各生成了4个占位符,总计8个,但传入的参数只有4个,必然触发参数数量不匹配的报错。
另外原代码存在几处语法笔误,需要先修正才能正常运行:

  • create_engine的连接字符串未包裹字符串引号
  • 定义placeholder时多写了一个赋值等号
  • query多行字符串未闭合三引号
  • pd.read_sql_query传入的SQL对象、参数名和前面定义的变量不匹配
解决方法

方法1:重复传入参数列表(最简单,适配短列表场景)

每个?占位符都需要对应一个独立入参,你只需要在传参时把原列表重复拼接一次,让传入的参数总数和占位符数量一致即可。元组/列表乘以2就可以快速实现元素重复,不需要手动写两遍列表。

修正后的可运行代码如下:

import pandas as pd
import datetime
from datetime import date
from sqlalchemy import create_engine

# 修正:连接字符串加引号
cnxn = create_engine("mssql+pyodbc://<connection_string>?driver=SQL+Server")
end_date = date.today().strftime('%Y-%m-%d')
start_date = (date.today() - datetime.timedelta(days=90)).strftime('%Y-%m-%d')

temp_list = ('item1',
    'item2',
    'item3',
    'item4')
# 修正:去掉多余的等号
placeholder = ','.join('?' for i in range(len(temp_list)))

# 修正:闭合三引号,同时把日期也改为参数化,避免SQL注入风险
query = f"""
    SELECT something
    FROM Table
    where date between ? and ?
        and name IN ({placeholder})
    UNION
    SELECT something
    FROM other_table
    where date between ? and ?
        and name IN ({placeholder})
"""

df = pd.read_sql_query(
    query, 
    cnxn, 
    # 按占位符顺序传参:2个日期参数 + 第一组IN参数 + 2个日期参数 + 第二组IN参数
    params=(start_date, end_date, *temp_list, start_date, end_date, *temp_list)
)
# 如果暂时不想改日期参数化,保持原f-string拼接日期的写法,params直接传 temp_list*2 即可

writer = pd.ExcelWriter('foo.xlsx', datetime_format='hh:mm:ss')
df.to_excel(writer, sheet_name='bar', index=False)
writer.close() # 新版本pandas推荐用close(),旧版本save()也可兼容

方法2:用CTE/临时表预存列表值(适配长列表场景)

如果你的IN列表元素很多,重复传参会让SQL语句变得冗余,这时候可以先通过CTE或者临时表把列表值提前存入,后面两个查询都直接关联这组值做过滤,只需要传一次列表参数即可。核心逻辑示例:

WITH item_filter(name) AS (
    SELECT ? UNION ALL SELECT ? UNION ALL SELECT ? UNION ALL SELECT ?
)
SELECT something
FROM Table t
INNER JOIN item_filter f ON t.name = f.name
where date between ? and ?
UNION
SELECT something
FROM other_table ot
INNER JOIN item_filter f ON ot.name = f.name
where date between ? and ?

这种写法下你只需要传一次列表参数+两个日期参数即可,适合列表元素超过20个的场景。

注意:不要为了省事直接把列表值拼接进SQL字符串,会带来SQL注入风险,参数化查询是最安全的做法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 05:31:36