2012-05-16 3 views
2

J'ai quelques tables de notification différentes, et je voudrais effectuer une union à travers chacune d'elles pour montrer à l'utilisateur toutes leurs notifications. Cependant, le syndicat ne fonctionne pas comme il le devrait.Comment l'union entre plusieurs tables dans SQLAlchemy?

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

Utilisation: user._get_notifications_query (unconfirmed_only = False) .Toutes()

SQL généré

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 

Je me attends quelque chose le long de ces lignes

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

De même, existe-t-il un moyen de trier les résultats d'union de SQLAlchemy?

EDIT

Je dois mentionner que sqlalchemy.sql.union() produit SQL correct, mais je ne sais pas comment faire usage de ce de l'ORM (retour/compter les enregistrements).

+0

Je dois construire des unions de plus de 2 requêtes, le nombre de requêtes en union est dynamique. sqlalchemy.sql.union() ne fonctionne pas. qu'est-ce que le syntaxt, je ne peux pas trouver dans doc – vishal

Répondre

2

Je ne pense pas que cela puisse fonctionner avec une union, même en supposant que la requête a été générée comme prévu. Vous interrogez trois types d'objets différents. Lorsque l'ORM récupère les lignes de la base de données, je ne vois aucun moyen de mapper les lignes à la bonne classe.

Une union dans ce cas n'a pas beaucoup de sens puisque la troisième colonne a une signification différente dans les trois tables.

Vous devez effectuer les trois requêtes séparément, sauf si vos trois types de notification héritent d'une classe mappée ORM commune. Dans ce cas, SQLAlchemy prend en charge l'interrogation des quatre types en même temps, mais pas avec UNION.

+0

Je ne veux pas nécessairement faire 3 requêtes séparées - pouvez-vous expliquer votre dernière déclaration plus en détail s'il vous plaît, parce que tous mes types de notification héritent d'une classe 'Notification'? – BDuelz

+0

Je n'ai jamais utilisé le support de SQLAlchemy pour l'héritage, je ne peux que vous diriger vers les docs: http://docs.sqlalchemy.org/en/rel_0_7/orm/inheritance.html. Notez cette phrase dans l'introduction: "Lorsque les mappeurs sont configurés dans une relation d'héritage, SQLAlchemy a la capacité de charger des éléments" polymorphiquement ", ce qui signifie qu'une seule requête peut renvoyer des objets de plusieurs types." –

+0

Gracias, je vais voir – BDuelz

1

Il est certainement possible d'unir différentes tables avec sqlalchemy, il vous suffit de spécifier quelles colonnes vous extrayez de chaque table pour qu'elles puissent être combinées correctement. Disons que vous avez des entités A et B, faites ceci:

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) 

Dans ce cas, tout ce que vous auriez à prendre en compte est que si A.someColumn et B.someOtherColumn ne peuvent pas être contraints au même type, votre DBMS pourrait paniquer :)

Pour un exemple dans le "monde réel", voir la ligne 85, 87 et 90:

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

Cela crée une sous-requête de deux tables différentes Unione de d ensemble. Cette sous-requête est ensuite utilisée ultérieurement dans une jointure et ses colonnes sont accessibles via .c.column comme d'habitude.

Questions connexes