sqlalchemy加入的别名没有来自两个表的列

时间:2011-09-29 16:28:49

标签: python join group-by sqlalchemy

我想要的只是TableA中按TableB列的一个列的计数,但当然我需要TableB中与每个计数相关联的项目。用代码更好地解释:

TableA和B是Model对象。

我尽力遵循this syntax

尝试运行此查询:

sq = session.query(TableA).join(TableB).\
        group_by(TableB.attrB).subquery()

countA = func.count(sq.c.attrA)
groupB = func.first(sq.c.attrB)   

print session.query(countA, groupB).all()     

但它给了我一个AttributeError(sq没有attrB)

我是SA的新手,我觉得很难学。 (欢迎链接到推荐的教育资源!)

1 个答案:

答案 0 :(得分:2)

当您从select语句中创建子查询时,可以从中访问的列必须位于columns子句中。举个例如:

这样的陈述
select x, y from mytable where z=5

如果我们想创建子查询,那么GROUP BY'z',这将不合法SQL:

select * from (select x, y from mytable where z=5) as mysubquery group by mysubquery.z

因为'z'不在“mysubquery”的columns子句中(因为'x'和'y'也应该在GROUP BY中,所以它也是非法的,但这是一个不同的问题)。

SQLAlchemy的工作方式完全相同。当你说查询(..)。子查询(),或在核心可选构造上使用alias()函数时,它意味着你将SELECT语句包装在括号中,给它一个(通常是生成的)名称,然后给它一个新的.c。只有那些列在“columns”子句中的集合,就像真正的SQL一样。

因此,您需要确保TableB(至少是您在外部处理的列)可用。您还可以将columns子句限制为所需的列:

sq = session.query(TableA.attrA, TableB.attrB).join(TableB).\
        group_by(TableB.attrB).subquery()

countA = func.count(sq.c.attrA)
groupB = func.first(sq.c.attrB)   

print session.query(countA, groupB).all()    

请注意,上述查询可能仅适用于MySQL,因为在使用分组时,在一般SQL中引用任何不属于聚合函数的列或GROUP BY的一部分是非法的。在这方面,MySQL有一个更宽松(和草率)的系统。

编辑:如果你想要没有零的结果:

import collections

letter_count = collections.defaultdict(int)
for count, letter in session.query(func.count(MyClass.id), MyClass.attr).group_by(MyClass.attr):
    letter_count[letter] = count

for letter in ["A", "B", "C", "D", "E", ...]:
    print "Letter %s has %d elements" % letter_count[letter]

note letter_count [someletter]默认为零,否则不会填充。