5

いくつかの異なる通知テーブルがあり、それらすべてに対して結合を実行して、ユーザーにすべての通知を表示したいと思います。しかし、組合は期待通りに機能していません。

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から集約されたユニオンの結果を並べ替える方法はありますか?

編集

それが正しいSQLを生成することを言及する必要がsqlalchemy.sql.union()ありますが、ORMからそれを利用する方法(レコードを返す/カウントする)がわかりません。

4

2 に答える 2

6

異なるテーブルを sqlalchemy で結合することは確かに可能です。適切に結合できるように、各テーブルからフェッチする列を指定するだけです。エンティティAとがあるとします。次Bのようにします。

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.someOtherColumndbms が異常になる可能性があるということだけです:)

「実世界」での例については、85、87、および 90 行目を参照してください。

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

これにより、結合された 2 つの異なるテーブルのサブクエリが作成されます。.c.columnそのサブクエリは後で結合で使用され、その列は通常どおりにアクセスされます。

于 2014-07-18T14:45:07.383 に答える
4

クエリが期待どおりに生成されたとしても、これはユニオンでは機能しないと思います。3 つの異なるオブジェクト タイプをクエリしています。ORM がデータベースから行を取得するときに、行を正しいクラスにマップする方法がわかりません。

この場合の UNION はあまり意味がありません。3 番目の列は 3 つのテーブルすべてで異なる意味を持っているからです。

3 つの通知タイプが共通の ORM マップ クラスから継承されない限り、3 つのクエリを個別に実行する必要があります。その場合、SQLAlchemy は 4 つの型を一度にクエリすることをサポートしますが、UNION を使用することはできません。

于 2012-05-16T05:44:04.297 に答える