sqlalchemy联合别名没有包含两张表的列
我想要的是从表A中获取数据,并按照表B中的某一列进行分组,当然我还需要知道每个计数对应的表B中的项目。用代码来解释会更清楚:
表A和表B都是模型对象。
我尽量按照这个语法来写。
我尝试运行这个查询:
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()
但是它给我返回了一个属性错误(sq没有attrB这个属性)。
我刚接触SQLAlchemy,觉得学习起来有点困难。(欢迎推荐一些学习资源!)
1 个回答
3
当你把一个选择语句变成子查询时,能从中访问的列必须在列的部分列出。比如说,有这样一个语句:
select x, y from mytable where z=5
如果我们想做一个子查询,然后按'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的工作方式也是一样的。当你使用query(..).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]如果没有被填充,默认是零。