【问题标题】:How to union across multiple tables in SQLAlchemy?如何在 SQLAlchemy 中跨多个表进行联合?
【发布时间】:2014-07-18 22:45:07
【问题描述】:

我有几个不同的通知表,我想对所有这些表执行联合,以向用户显示他们的所有通知。但是,工会并没有发挥应有的作用。

Python 代码

def _get_notifications_query(self, unconfirmed_only=True):
    '''
    Return base query to return this users notifications.

    @param unconfirmed_only
    @return Query object
    '''        
    requests = (
        DBSession.query(FriendshipRequestNotification)
        .outerjoin(UserFriendshipRequestNotification,
                   UserFriendshipRequestNotification.notification_id==FriendshipRequestNotification.id)
        .filter(UserFriendshipRequestNotification.user_id==self.id))
    confirmations = (
        DBSession.query(FriendshipConfirmationNotification)
        .outerjoin(UserFriendshipConfirmationNotification,
                   UserFriendshipConfirmationNotification.notification_id==FriendshipConfirmationNotification.id)
        .filter(UserFriendshipConfirmationNotification.user_id==self.id))
    comments = (
        DBSession.query(CommentNotification)
        .outerjoin(UserCommentNotification,
                   UserCommentNotification.notification_id==CommentNotification.id)
        .filter(UserCommentNotification.user_id==self.id))

    if unconfirmed_only:
        requests.filter(UserFriendshipRequestNotification.is_confirmed==False)
        confirmations.filter(UserFriendshipConfirmationNotification.is_confirmed==False)
        comments.filter(UserCommentNotification.is_confirmed==False)

    return requests.union(confirmations, comments)

使用:user._get_notifications_query(unconfirmed_only=False).all()

SQL 生成

SELECT anon_1.friendship_request_notifications_id AS anon_1_friendship_request_notifications_id, anon_1.friendship_request_notifications_created_at AS anon_1_friendship_request_notifications_created_at, anon_1.friendship_request_notifications_requester_id AS anon_1_friendship_request_notifications_requester_id 
FROM (SELECT friendship_request_notifications.id AS friendship_request_notifications_id, friendship_request_notifications.created_at AS friendship_request_notifications_created_at, friendship_request_notifications.requester_id AS friendship_request_notifications_requester_id 
FROM friendship_request_notifications LEFT OUTER JOIN users_friendship_request_notifications ON users_friendship_request_notifications.notification_id = friendship_request_notifications.id 
WHERE users_friendship_request_notifications.user_id = ? UNION SELECT friendship_confirmation_notifications.id AS friendship_confirmation_notifications_id, friendship_confirmation_notifications.created_at AS friendship_confirmation_notifications_created_at, friendship_confirmation_notifications.accepter_id AS friendship_confirmation_notifications_accepter_id 
FROM friendship_confirmation_notifications LEFT OUTER JOIN users_friendship_confirmation_notifications ON users_friendship_confirmation_notifications.notification_id = friendship_confirmation_notifications.id 
WHERE users_friendship_confirmation_notifications.user_id = ? UNION SELECT comment_notifications.id AS comment_notifications_id, comment_notifications.created_at AS comment_notifications_created_at, comment_notifications.comment_id AS comment_notifications_comment_id 
FROM comment_notifications LEFT OUTER JOIN users_comment_notifications ON users_comment_notifications.notification_id = comment_notifications.id 
WHERE users_comment_notifications.user_id = ?) AS anon_1

我预计会有类似的情况

SELECT * FROM friendship_request_notifications
UNION
SELECT * FROM friendship_confirmation_notifications
UNION 
SELECT * FROM comment_notifications

另外,有没有办法对 SQLAlchemy 中的聚合联合结果进行排序?

编辑

我应该提到sqlalchemy.sql.union() 产生了正确的 SQL,但我不知道如何从 ORM 中使用它(返回/计算记录)。

【问题讨论】:

  • 我需要建立超过 2 个查询的联合,联合中的查询数量是动态的。 sqlalchemy.sql.union() 不起作用。什么是语法,在文档中找不到

标签: python sqlalchemy union


【解决方案1】:

当然可以使用 sqlalchemy 合并不同的表,您只需指定要从每个表中提取的列,以便它们可以正确组合。假设您有实体 AB,请执行以下操作:

from sqlalchemy.sql.expression import label
...

a = session.query(label('col1', A.someColumn))
b = session.query(label('col1', B.someOtherColumn))
both = a.union_all(b)

在这种情况下,您需要注意的是,如果不能将 A.someColumnB.someOtherColumn 强制转换为同一类型,您的 dbms 可能会崩溃:)

关于“现实世界”中的示例,请参见第 85、87 和 90 行:

https://gerrit.wikimedia.org/r/#/c/147312/4/wikimetrics/metrics/rolling_active_editor.py

这会创建一个合并在一起的两个不同表的子查询。该子查询随后将在连接中使用,并像往常一样通过.c.column 访问其列。

【讨论】:

  • 这个答案帮助我合并了两个不同的表。谢谢。
  • 请注意,这里的label 在每个表中的列名称不同时使用。如果它们具有相同的名称,则可以省略,例如query(A.someColumn).
【解决方案2】:

我认为这不适用于联合,即使假设查询是按照您的预期生成的。您正在查询三种不同的对象类型。当 ORM 从数据库中取回行时,我看不到将行映射到正确类的方法。

在这种情况下,UNION 没有多大意义,因为第三列在所有三个表中具有不同的含义。

您应该分别执行这三个查询,除非您的三个通知类型继承自一个通用的 ORM 映射类。在这种情况下,SQLAlchemy 支持同时查询这四种类型,尽管不使用 UNION。

【讨论】:

  • 我不一定介意进行 3 个单独的查询 - 请您更彻底地解释您的最后一条语句,因为我所有的通知类型都继承自 Notification 类?
  • 我从未使用过 SQLAlchemy 对继承的支持,我只能将您指向文档:docs.sqlalchemy.org/en/rel_0_7/orm/inheritance.html。请注意引言中的这句话:“当映射器配置为继承关系时,SQLAlchemy 具有“多态”加载元素的能力,这意味着单个查询可以返回多种类型的对象。”
  • 谢谢,我去看看
猜你喜欢
  • 2014-06-28
  • 1970-01-01
  • 2022-12-10
  • 2023-04-04
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 2019-08-15
  • 1970-01-01
相关资源
最近更新 更多