SQLAlchemy查询显示错误"无法加入表/可选择的工作流程'对自己"

时间:2015-08-01 22:48:44

标签: postgresql sqlalchemy

我写了一个SQL查询,我试图移植到SQLAlchemy,但收到以下错误:

sqlalchemy.exc.InvalidRequestError: Can't join table/selectable 'workflows' to itself

SQL(工作):

SELECT
   w.user_id, COUNT(l.id) 
FROM
   logs as l
INNER JOIN
   workflows as w 
   ON l.workflow_id = w.id
WHERE
   l.type = 's'
   AND l.timestamp > extract(epoch from now()) - 86400
GROUP BY
   w.user_id;

SQLAlchemy(不工作):

session.query(
   Workflow.user_id, func.count(Log.id)
).join(
   Workflow, Workflow.id == Log.workflow_id
).where(
   Log.type == 's', Log.timestamp > time.time() - 86400
).group_by(
   Workflow.user_id
).all()

这是预期的输出:

+----------+---------+
|  user_id |  count  |
+----------+---------+
| 1        | 5       |
| 2        | 10      |
+----------+---------+

我做错了什么?

2 个答案:

答案 0 :(得分:6)

部分.query(Workflow.user_id, func.count(Log.id))WorkflowLog添加到您的查询中。第一个模型标记为主表,其他模型标记为辅助表。如果之后没有调用.join(),则主表和辅助表都将添加到FROM子句中。如果有.join()的调用,它会将收到的表移动到JOIN子句。这里重要的是.join()只能应用于辅助表。

问题是您对.join(Workflow, Workflow.id == Log.workflow_id)的调用会尝试将主表标记为已加入。要解决问题,您需要加入辅助表:.join(Log, Workflow.id == Log.workflow_id)

您可以添加echo=True以查看SQLAlchemy生成的SQL。调试查询非常方便。或者您可以compile单个查询来查看生成的SQL。

答案 1 :(得分:0)

如前所述,查询的主要实体是Workflow,因此联接正在尝试将Workflow与其自身联接,这是不可能的,至少在没有使用别名的情况下是不可能的。

除了简单地重新排序联接之外,还可以使用Query.select_from()来显式控制联接的左侧:

session.query(
    Workflow.user_id, func.count(Log.id)
).select_from(
    Log
).join(
    Workflow, Workflow.id == Log.workflow_id
).filter(
    Log.type == 's', Log.timestamp > time.time() - 86400
).group_by(
    Workflow.user_id
).all()