2010-11-17 23 views
16

Estoy escribiendo una consulta ActiveRecord de Rails 3 utilizando la sintaxis "where", que utiliza tanto SQL IN como el operador SQL OR y no puedo entender cómo usa ambos juntos.Rails 3 Consulta de ActiveRecord utilizando operadores SQL IN y SQL OR

obras Este código (en mi modelo de usuario):

Question.where(:user_id => self.friends.ids) 
#note: self.friends.ids returns an array of integers 

pero

Question.where(:user_id => self.friends.ids OR :target => self.friends.usernames) 

devuelve este error

syntax error, unexpected tCONSTANT, expecting ')' 
...user_id => self.friends.ids OR :target => self.friends.usern... 

alguna idea de cómo escribir esto en rieles este código, ¿o simplemente cuál debería ser la consulta SQL sin formato?

Respuesta

-7

SQL prima

SELECT * 
FROM table 
WHERE user_id in (LIST OF friend.ids) OR target in (LIST OF friends.usernames) 

con cada lista separada por comas. No sé bien las cosas de Rails ActiveRecord. Para Y usted acaba de poner una coma entre esas dos condiciones, pero idk sobre O

+0

Gracias! La consulta exacta que utilicé fue: Question.where ('target IN (?) O user_id IN (?)', Self.friends.usernames, self.friends.ids) – kateray

+0

ok genial, me olvidé de eso. Siento que deberían ser una forma dentro del formato => hash. no debería necesitar un patrón de cadena solo para agregar O entre 2 condiciones válidas, pero a quién le importa que lo tenga. –

+13

la idea de registro activo es independiente de la base de datos, por lo que no se debe considerar utilizar sql en rieles como la mejor solución, excepto cuando el rendimiento se degrada, que no es el caso en esta consulta – nunopolonia

45

No es necesario utilizar SQL crudo, simplemente proporcionar el patrón como una cadena, y añadir parámetros con nombre:

Question.where('user_id in (:ids) or target in (:usernames)', 
       :ids => self.friends.ids, :usernames => self.friends.usernames) 

o parámetros posicionales:

Question.where('user_id in (?) or target in (?)', 
       self.friends.ids, self.friends.usernames) 

también puede utilizar la excelente Squeel gema, como @erroric señaló en su respuesta (bloque my { } sólo es necesario si se necesita acceso a self o instancia variables):

Question.where { user_id.in(my { self.friends.ids }) | 
       target.in(my { self.friends.usernames }) } 
+0

Hola, tipo de hombre, necesito ayuda .. Cómo escribir una consulta si necesito seleccionar todos los mensajes entre dos usuarios (digamos id1 e id2) y el mensaje tiene sender_id y receiver_id. Entonces necesito seleccionar "todos los mensajes cuyo ((sender_id = id1 y reciver_id = id2) o (sender_id = id2 y reciver_id = id1))". Necesito ordenarlos y paginarlos, lo cual no se puede hacer si hago dos consultas por separado y luego las agrego (tendré el resultado deseado, pero la paginación se vuelve difícil). Así que por favor ayúdenme a escribir una consulta de línea única para esto. Cualquier ayuda será apreciada. – zeal

+0

@zeal, abra una nueva pregunta, describiendo lo que ya ha intentado y cómo podemos ayudarlo. La comunidad es genial, pero debes aprender a usarla. –

9

Aunque los carriles 3 AR no le da una u operador todavía se puede lograr el mismo resultado sin tener que ir todo el camino a SQL y utilizar Arel directamente. Con esto quiero decir que usted puede hacerlo de esta manera:

t = Question.arel_table 
Question.where(t[:user_id].in(self.friends.ids).or(t[:username].in(self.friends.usernames))) 

Algunos podrían decir que no es tan bonita, algunos podrían decir que es bastante simple, ya que no incluye SQL. De todos modos que sin duda podría ser más bonita y hay una joya para él también: MetaWhere

Para más información ver esta Railscast: http://railscasts.com/episodes/215-advanced-queries-in-rails-3 y MetaWhere sitio: http://metautonomo.us/projects/metawhere/

ACTUALIZACIÓN: Más tarde Ryan Bates ha hecho otra Railscast sobre metawhere y metabuscador: http://railscasts.com/episodes/251-metawhere-metasearch Más tarde, aunque Metawhere (y la búsqueda) se han convertido en gemas más o menos heredadas. Es decir. ni siquiera funcionan con Rails 3.1. El autor sintió que (Metawhere y búsqueda) necesitaba una reescritura drástica. Tanto que en realidad fue por una nueva joya todos juntos. El sucesor de Metawhere es Squeel. Lea más sobre el anuncio autores aquí: http://erniemiller.org/2011/08/31/rails-3-1-and-the-future-of-metawhere-and-metasearch/ y echa un vistazo a la página web del proyecto: http://erniemiller.org/projects/squeel/ "Metabúsqueda 2.0" se llama Ransack y se puede leer algo al respecto desde aquí: http://erniemiller.org/2011/04/01/ransack-the-library-formerly-known-as-metasearch-2-0/

6

Como alternativa, puede usar Squeel. Para mí, es más simple.Esto se puede hacer tanto en las operaciones o (|) EN (>>) y utilizando la siguiente sintaxis:

Question.where{(:user_id >> my{friends.id}) | (:target >> my{friends.usernames})} 

general envuelvo mis condiciones en (...) para asegurar el orden apropiado de operación - tanto el INS suceder antes de que el OR.

El bloque my{...} ejecuta métodos desde el contexto self como se define antes de la llamada squeel - en este caso Question. Dentro del bloque Squeel, self se refiere a un objeto Squeel y no al objeto Question (see the Squeel Readme for more). Puede solucionar esto utilizando el contenedor my{...} para restaurar el contexto original.

+1

Se ve bien, pero [bloquearon '(()' (https://github.com/ernie/squeel#compatibility-with-active-record) de Active Record que parece desafortunado. – crizCraig

Cuestiones relacionadas