当您从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”的列子句(它也是非法的,因为'x'和'y'也应该在GROUP BY中,但这是一个不同的问题)。
SQLAlchemy的工作方式完全相同。当你说查询(..)。subquery(),或者在核心可选结构上使用alias()函数时,这意味着你将你的SELECT语句包装在括号中,给它一个(通常是生成的)名字,并给它一个新的.c。只有那些位于“列”子句中的列才是真正的SQL。
所以在这里你需要确保TableB,至少是你在外部处理的列是可用的。您还可以限制列子句只是那些列,你需要:
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]
注letter_count [someletter]默认为零否则不填充。
'FIRST()'不是一个sql标准函数,你连接了哪些DBMS? – SingleNegationElimination
@TokenMacGuy好的。那么我的问题适用,如果你用'最大'替换'第一',但没有理由比较应该是相同的所有值。我正在使用mySQL引擎。 – Paul