sqlalchemy 连接别名没有两个表中的列

发布于 2024-12-06 23:16:42 字数 560 浏览 0 评论 0原文

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

TableA 和 B 是 Model 对象。

我正在尝试尽可能遵循 此语法能。

尝试运行此查询:

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 的新手,我发现很难学习。 (欢迎链接到推荐的教育资源!)

All I want is the count from TableA grouped by a column from TableB, but of course I need the item from TableB each count is associated with. Better explained with code:

TableA and B are Model objects.

I'm trying to follow this syntax as best I can.

Trying to run this query:

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()     

But it gives me an AttributeError (sq does not have attrB)

I'm new to SA and I find it difficult to learn. (links to recommended educational resources welcome!)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

じее 2024-12-13 23:16:42

当您从 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 的工作方式完全相同。当您说 query(..).subquery() 或在核心可选构造上使用 alias() 函数时,这意味着您将 SELECT 语句括在括号中,为其指定一个(通常生成的)名称,并为其指定名称一个新的.c。仅包含“column”子句中的列的集合,就像真正的 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]

请注意 letter_count[someletter] 如果未填充,则默认为零。

When you make a subquery out of a select statement, the columns that can be accessed from it must be in the columns clause. Take for example a statement like:

select x, y from mytable where z=5

If we wanted to make a subquery, then GROUP BY 'z', this would not be legal SQL:

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

Because 'z' is not in the columns clause of "mysubquery" (it's also illegal since 'x' and 'y' should be in the GROUP BY as well, but that's a different issue).

SQLAlchemy works the same exact way. When you say query(..).subquery(), or use the alias() function on a core selectable construct, it means you're wrapping your SELECT statement in parenthesis, giving it a (usually generated) name, and giving it a new .c. collection that has only those columns that are in the "columns" clause, just like real SQL.

So here you'd need to ensure that TableB, at least the column you're dealing with externally, is available. You can also limit the columns clause to just those columns you need:

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()    

Note that the above query probably only works on MySQL, as in general SQL it's illegal to reference any columns that aren't part of an aggregate function, or part of the GROUP BY, when grouping is used. MySQL has a more relaxed (and sloppy) system in this regard.

edit: if you want the results without the zeros:

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] defaults to zero if otherwise not populated.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文