J'ai écrit quelques requêtes complexes (du moins pour moi) avec l'interface de requête de Ruby on Rail:
watched_news_posts = Post.joins(:news => :watched).where(:watched => {:user_id => id})
watched_topic_posts = Post.joins(:post_topic_relationships => {:topic => :watched}).where(:watched => {:user_id => id})
Ces deux requêtes fonctionnent bien par elles-mêmes. Les deux renvoient des objets Post. Je voudrais combiner ces messages en une seule ActiveRelation. Puisqu'il pourrait y avoir des centaines de milliers de messages à un moment donné, cela doit être fait au niveau de la base de données. S'il s'agissait d'une requête MySQL, je pourrais simplement utiliser l' UNION
opérateur. Est-ce que quelqu'un sait si je peux faire quelque chose de similaire avec l'interface de requête de RoR?
ruby-on-rails
activerecord
union
active-relation
LandonSchropp
la source
la source
Post.watched_news_posts.watched_topic_posts
. Vous devrez peut-être envoyer des paramètres aux portées pour des éléments tels que:user_id
et:topic
.find_by_sql("#{watched_news_posts.to_sql} UNION #{watched_topic_posts.to_sql}")
. Je n'ai pas testé cela, alors dites-moi comment cela se passe si vous l'essayez. De plus, il existe probablement des fonctionnalités ARel qui fonctionneraient.find_by_sql
ne peuvent malheureusement pas être utilisés avec d'autres requêtes chaînables, ce qui signifie que je dois maintenant réécrire mes filtres et requêtes will_paginate également. Pourquoi ActiveRecord ne prend-il pas en charge uneunion
opération?Réponses:
Voici un petit module rapide que j'ai écrit qui vous permet de UNION plusieurs portées. Il renvoie également les résultats sous forme d'instance d'ActiveRecord :: Relation.
Voici l'essentiel: https://gist.github.com/tlowrimore/5162327
Éditer:
Comme demandé, voici un exemple du fonctionnement d'UnionScope:
la source
J'ai également rencontré ce problème, et maintenant ma stratégie de choix consiste à générer du SQL (à la main ou à l'aide
to_sql
d'une portée existante), puis à le coller dans lafrom
clause. Je ne peux pas garantir que ce soit plus efficace que votre méthode acceptée, mais c'est relativement facile pour les yeux et vous donne un objet ARel normal.Vous pouvez également le faire avec deux modèles différents, mais vous devez vous assurer qu'ils "se ressemblent" tous les deux à l'intérieur de UNION - vous pouvez utiliser
select
sur les deux requêtes pour vous assurer qu'ils produiront les mêmes colonnes.la source
#or
en charge dans mon projet Rails 4. En supposant le même modèle:klass.from("(#{to_sql} union #{other_relation.to_sql}) as #{table_name}")
Sur la base de la réponse d'Olives, j'ai trouvé une autre solution à ce problème. Cela ressemble un peu à un hack, mais il renvoie une instance de
ActiveRelation
, ce que je cherchais en premier lieu.J'apprécierais toujours si quelqu'un a des suggestions pour optimiser cela ou améliorer les performances, car il exécute essentiellement trois requêtes et se sent un peu redondant.
la source
Vous pouvez également utiliser Brian Hempel de active_record_union joyau qui se prolonge
ActiveRecord
avec uneunion
méthode pour les portées.Votre requête serait comme ceci:
Espérons que cela sera éventuellement fusionné dans
ActiveRecord
un jour.la source
Que diriez-vous...
la source
pluck
appel est une requête en soi..order
ou.paginate
... Il garde les classes ormPourriez-vous utiliser un OR au lieu d'un UNION?
Ensuite, vous pouvez faire quelque chose comme:
(Puisque vous rejoignez la table surveillée deux fois, je ne sais pas trop quels seront les noms des tables pour la requête)
Comme il y a beaucoup de jointures, cela peut également être assez lourd sur la base de données, mais il peut être optimisé.
la source
On peut soutenir que cela améliore la lisibilité, mais pas nécessairement les performances:
Cette méthode retourne un ActiveRecord :: Relation, vous pouvez donc l'appeler comme ceci:
la source
Il existe une gemme active_record_union. Cela pourrait être utile
https://github.com/brianhempel/active_record_union
la source
Je voudrais simplement exécuter les deux requêtes dont vous avez besoin et combiner les tableaux d'enregistrements renvoyés:
Ou, au moins, testez-le. Pensez-vous que la combinaison de tableaux en rubis sera beaucoup trop lente? En regardant les requêtes suggérées pour contourner le problème, je ne suis pas convaincu qu'il y aura une telle différence de performances.
la source
Dans un cas similaire, j'ai additionné deux tableaux et utilisé
Kaminari:paginate_array()
. Solution très agréable et fonctionnelle. Je n'ai pas pu utiliserwhere()
, car je dois additionner deux résultats différentsorder()
sur la même table.la source
Moins de problèmes et plus facile à suivre:
Donc à la fin:
la source
scopes.drop(1).reduce(where(id: scopes.first)) { |query, scope| query.or(where(id: scope)) }
Thx!Elliot Nelson a bien répondu, sauf le cas où certaines relations sont vides. Je ferais quelque chose comme ça:
fin
la source
Voici comment j'ai rejoint des requêtes SQL en utilisant UNION sur ma propre application ruby on rails.
Vous pouvez utiliser ce qui suit comme inspiration sur votre propre code.
Ci-dessous est le UNION où j'ai joint les portées ensemble.
la source