Вопрос по python – Как объединить несколько таблиц в SQLAlchemy?

3

У меня есть несколько разных таблиц уведомлений, и я хотел бы объединить их, чтобы показать пользователю все их уведомления. Тем не менее, профсоюз не работает как следует.

Python code

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 (unsfirmed_only = False) .all ()

SQL generated

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

I expect something along these lines

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

Кроме того, есть ли способ сортировать агрегированные результаты объединения из SQLAlchemy?

EDIT

Я должен упомянуть, чтоsqlalchemy.sql.union() производит правильный SQL, но я не знаю, как использовать это из ORM (возврат / подсчет записей).

Мне нужно создать объединения из более чем 2 запросов, количество запросов в объединении являются динамическими. sqlalchemy.sql.union () не работает. что такое синтаксис, не могу найти в документе vishal

Ваш Ответ

2   ответа
2

можно объединить разные таблицы с помощью 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.someColumn а такжеB.someOtherColumn не может быть приведен к тому же типу, ваши dbms могут взбеситься :)

Например, в «реальном мире» см. Строки 85, 87 и 90:

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

Это создает подзапрос двух разных таблиц, объединенных вместе. Этот подзапрос затем используется в соединении, и его столбцы доступны через.c.column по-прежнему.

2

Я не думаю, что это может работать с объединением, даже если предположить, что запрос был сгенерирован так, как вы ожидаете. Вы запрашиваете три разных типа объектов. Когда ORM возвращает строки из базы данных, я не вижу способа сопоставить строки с правильным классом.

В этом случае UNION не имеет большого смысла, поскольку третий столбец имеет разное значение во всех трех таблицах.

Вы должны выполнять три запроса по отдельности, если только ваши три типа уведомлений не наследуются от общего класса ORM. В этом случае SQLAlchemy поддерживает запросы всех четырех типов одновременно, но не с помощью UNION.

Грасиас, я посмотрю BDuelz
Я не возражаю против выполнения трех отдельных запросов - не могли бы вы объяснить свое последнее заявление более подробно, потому что все мои типы уведомлений наследуются отNotification учебный класс? BDuelz
Я никогда не использовал поддержку наследования SQLAlchemy, я могу лишь указать вам на документы:docs.sqlalchemy.org/en/rel_0_7/orm/inheritance.html, Обратите внимание на это предложение во введении: «Когда преобразователи настроены на отношения наследования, SQLAlchemy имеет возможность загружать элементы», «полиморфно», что означает, что один запрос может возвращать объекты нескольких типов.

Похожие вопросы