2009-06-17 11 views
2

J'ai 3 modèles: Livres, Notifications et Types de Notification. Les livres ont des notifications car le modèle de notification a un book_id. Les notifications ont un NOTIFICATION_TYPE comme le modèle de notification a un notification_type_idSQL noob a besoin d'aide pour écrire une requête Rails impliquant des jointures et peut-être se croiser

Je veux tous les livres créés entre date1 et date2

books_set1 = Book.find :all, :conditions => ["created_at <= ? AND show_time >= ?", max_date, min_date] 

Mais je ne veux pas les livres qui ont des notifications de notification.notification_type_id = 1 et idéalement je vous dire ceci en se référant à notification_type.name donc je ne voudrais pas que les livres qui ont des notifications de notification.notification_type.name = « type1 »

S'il y a eu une notification de type1 créé pour un livre déjà, je ne Je veux qu'il revienne dans l'ensemble (parce que je vais c reate les notifications de ce type avec l'ensemble retourné). Je ne suis pas sûr s'il y a un moyen de faire cela en une seule requête, je pense avoir besoin de 2 requêtes avec et INTERSECT - le premier que j'ai déjà inclus dans ce post et le second dont je ne suis pas sûr. Mais en pseudo-code, je pense que c'est ce qu'il doit faire:

notification_type_id = Notification.find_by_name('type1') 
get all notifications where notification_id = notification_type_id 
set2 = get the associated book set from the notification set (since each notification has one book) 

alors je ne set1 - set2

MISE À JOUR

Merci à l'aide que j'ai écrit deux requêtes obtenez-moi les résultats souhaités. J'aimerais pour que cela soit dans une requête si quelqu'un sait comment le faire:

books_in_range = Book.find :all, :conditions => ["created_at <= ? AND created_at >= ?", max_date, min_date] 
books_without_these_notifications = Book.find(:all, :joins => { :notifications => :notification_type }, :conditions => ["notification_types.name = ?","type1"]) 
books_to_consider = books_in_range - books_without_these_reminders 

Encore une fois, l'idée est d'obtenir tous les livres qui n'ont pas de notification de type1 créé et se situent dans une plage de dates .

+1

Avez-vous essayé l'option NOT EXISTS dans ma réponse? Il serait presque certainement plus efficace que d'obtenir tous les livres dans la plage de dates et ensuite obtenir tous ceux avec des notifications de type1. – Shadwell

+0

ça ne marche pas, la notification_id n'est pas définie ... mais je la corrige et je vous tiendrai au courant. Merci de me le rappeler....J'ai raccroché à la réponse de molf – Tony

+1

J'ai modifié pour corriger - l'association était à l'envers entre les livres et les notifications. – Shadwell

Répondre

2

Vous pouvez le faire avec pas mais je suis EXISTE ne sais pas comment il serait efficace:

Book.find(
    :all, 
    :conditions => 
    ['created_at <= ? AND show_time >= ? AND 
     NOT EXISTS 
     (SELECT * FROM notifications 
     INNER JOIN notification_types ON notifications.notification_type_id = notification_types.id 
     WHERE notification_types.name = ? AND notifications.book_id = books.id)', 
    max_date, min_date, 'type1' 
    ]) 

Vous pourriez être en mesure de venir à lui d'une direction différente et garder une trace de ceux qui avez eu une notification de type1 envoyé en ajoutant un booléen aux livres ou à un autre objet joint directement aux livres. Votre requête pourrait alors être:

Book.find(:all, 
    :conditions => 
    ['created_at <= ? AND show_time >= ? AND 
     type1_notification_sent = ?', 
    max_date, min_date, false 
    ]) 
+0

je voudrais mais il peut y avoir comme 30 types de notifications à la fin de ce projet – Tony

+0

Assez juste. Ça vaut le coup d'essayer! – Shadwell

0
SELECT books.* FROM books WHERE books.created_at <= ? AND books.show_time >= ? AND 
    notifications.name <> 'type1' 
LEFT OUTER JOIN notifications ON notifications.book_id = books.id AND 
    notification.name = 'type1' 

Cela fonctionnerait, j'imagine.

3

Ce qui suit devrait fonctionner:

Book.scoped(:conditions => ["created_at <= ? AND show_time >= ?", max_date, 
    min_date]).find(:all, :joins => { :notifications => :notification_types }, 
    :conditions => ["notification_type.name <> ?", "type1"]) 

Extrait certains des arguments en named_scope s ou variables locales pour plus de clarté supplémentaire.

Mis à jour pour refléter la négation.

+0

hmmm ... essayant de le détecter. un problème est qu'un livre n'a pas beaucoup de rappels (il le fait théoriquement, mais j'ai fait en sorte que les utilisateurs aient de nombreux rappels puisque c'est comme ça que j'y accèderai généralement). aussi ne retournerait-il pas tous les livres qui ont la notification type1? Je veux finir avec des livres qui n'ont pas de type de notification1 – Tony

+0

rappels = notifications – Tony

+0

@Tony, mis à jour. Désolé, j'ai manqué la négation. – molf

Questions connexes