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

如何在SQLAlchemy原生SQL查询中使用PostgreSQL VALUES列表

解决SQLAlchemy原生SQL中PostgreSQL VALUES列表的参数传递问题

问题分析

你当前使用expanding=True绑定列表参数时,SQLAlchemy会将列表展开为同一行的多个值(如VALUES (%s, %s, %s)),但PostgreSQL的VALUES表构造器需要每个值作为独立行(如VALUES (%s), (%s), (%s)),因此需要调整参数绑定的方式。

解决方案

方案一:动态生成VALUES占位符

手动根据列表长度生成对应数量的独立占位符,每个占位符对应一个参数,确保生成符合要求的VALUES结构:

修改save_new方法如下:

def save_new(self, companies):
    tickers = ['A', 'B', 'C']
    # 生成每个值对应的占位符,格式为(:t0), (:t1), ...
    placeholders = ", ".join([f":t{i}" for i in range(len(tickers))])
    # 拼接完整SQL语句
    query_text = f'''
            SELECT input_values.ticker
            FROM (VALUES {placeholders}) as input_values(ticker)
            '''
    database_engine = self.__database_connection.get_engine()
    with database_engine.connect() as connection:
        query = text(query_text)
        # 构造参数字典,每个占位符对应一个ticker值
        params = {f"t{i}": ticker for i, ticker in enumerate(tickers)}
        result = connection.execute(query, params)
        new_tickers = [row[0] for row in result]
        logging.info(new_tickers)

方案二:使用PostgreSQL的unnest函数替代VALUES

如果场景允许,可利用PostgreSQL的unnest函数将数组直接转为行,这种方式参数传递更简洁:

from sqlalchemy import ARRAY, String

def save_new(self, companies):
    tickers = ['A', 'B', 'C']
    query_text = '''
            SELECT unnest(:input_values) as ticker
            '''
    database_engine = self.__database_connection.get_engine()
    with database_engine.connect() as connection:
        query = text(query_text).bindparams(
            bindparam('input_values', expanding=True, type_=ARRAY(String))
        )
        result = connection.execute(query, {'input_values': tickers})
        new_tickers = [row[0] for row in result]
        logging.info(new_tickers)

方案三:混合SQLAlchemy表达式与原生SQL

利用SQLAlchemy的values()构造器生成正确的VALUES子句,再嵌入到原生SQL中,自动处理参数绑定:

from sqlalchemy import values, column, String

def save_new(self, companies):
    tickers = ['A', 'B', 'C']
    database_engine = self.__database_connection.get_engine()
    # 构造VALUES子句的SQLAlchemy表达式
    vals_clause = values(column('ticker', String)).data([(t,) for t in tickers])
    # 编译表达式为SQL字符串和参数字典
    vals_sql, vals_params = vals_clause.compile(
        dialect=database_engine.dialect,
        compile_kwargs={"literal_binds": False}
    ).as_sql()
    # 拼接原生SQL
    query_text = f'''
            SELECT input_values.ticker
            FROM ({vals_sql}) as input_values(ticker)
            '''
    with database_engine.connect() as connection:
        query = text(query_text)
        result = connection.execute(query, vals_params)
        new_tickers = [row[0] for row in result]
        logging.info(new_tickers)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 07:57:43