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

SqlAlchemy的array_agg函数是否支持多列或整行聚合?

问题描述

在PostgreSQL中可以通过原生SQL实现聚合整行数据到数组:

SELECT 
     array_agg(users.*) 
FROM users 
WHERE 
     l_name LIKE 'Br%' 
GROUP BY f_name;

但用SQLAlchemy实现时,会抛出报错:

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) can't adapt type 'InstrumentedAttribute'

尝试仅聚合单列(如下)可以正常运行,但只能返回单列值,无法满足整行数据的需求:

query: Query[User] = session.query(array_agg(self.user.f_name))

显式指定多列组成元组的方式也会触发相同报错:

query: Query[User] = session.query(array_agg((self.user.f_name, self.user.l_name))))
解决方案

方法1:直接传递模型实体到array_agg(SQLAlchemy 1.4+)

SQLAlchemy 1.4及以上版本支持直接将模型实体传入array_agg,会自动转换为SQL中的users.*:

from sqlalchemy import func

# 生成聚合整行数据的查询
query = session.query(func.array_agg(self.user))\
               .filter(self.user.l_name.like('Br%'))\
               .group_by(self.user.f_name)

# 执行查询并获取结果
results = query.all()
# 每个结果中的数组元素会映射为User对象
for row in results:
    aggregated_users = row[0]
    for user in aggregated_users:
        print(user.f_name, user.l_name)

方法2:使用func.row()包裹所有列(兼容旧版本)

如果使用的是SQLAlchemy旧版本,或者需要更明确地控制行结构,可以用func.row()包裹模型的所有列,生成数据库层面的行构造器:

from sqlalchemy import func

# 获取模型的所有列
user_columns = self.user.__table__.columns

# 聚合整行数据
query = session.query(func.array_agg(func.row(*user_columns)))\
               .filter(self.user.l_name.like('Br%'))\
               .group_by(self.user.f_name)

# 执行查询后,可将行数据转换为User对象
results = query.all()
for row in results:
    user_rows = row[0]
    user_objects = [User(**dict(zip(self.user.__table__.columns.keys(), ur))) for ur in user_rows]

方法3:结合cast实现类型映射

如果需要确保聚合结果能正确映射为模型对象,可以用cast将行数据转换为PostgreSQL的RECORD类型:

from sqlalchemy import func, cast, ARRAY
from sqlalchemy.dialects.postgresql import RECORD

query = session.query(
    func.array_agg(cast(self.user, RECORD)).label('aggregated_users')
).filter(self.user.l_name.like('Br%')).group_by(self.user.f_name)

results = query.all()
for row in results:
    user_objects = [User(**dict(zip(User.__table__.columns.keys(), u))) for u in row.aggregated_users]

报错原因说明

之前尝试的(self.user.f_name, self.user.l_name)元组写法,会被SQLAlchemy识别为Python本地元组,而非PostgreSQL的行构造器,导致psycopg2无法适配InstrumentedAttribute类型。必须使用SQLAlchemy提供的func.row()或直接传递模型实体,才能生成正确的SQL行表达式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 04:50:28