2011-03-14 18 views
10

Supongamos que tenemos el siguiente:¿Hay alguna forma de invertir una consulta ActiveRecord :: Relation?

irb> Post.where(:hidden => true).to_sql 
=> "SELECT `posts`.* FROM `posts` WHERE posts.hidden = 1" 

Podríamos conseguir de alguna manera una consulta SQL invertida fuera de él?

Lo que estoy buscando, probablemente debería tener este aspecto:

irb> Post.where(:hidden => true).invert.to_sql 
=> "SELECT `posts`.* FROM `posts` WHERE NOT (posts.hidden = 1)" 
+1

donde (: oculto => falso) – jenjenut233

+6

Hmm. Mala votación del comentario 'where (: hidden => false)' de alguien. Ese código * no * generará el tipo de SQL que el OP está buscando. – Zabba

Respuesta

16

Con una sintaxis diferente, sí. Ejemplo:

posts = Post.scoped.table # or Arel::Table.new("posts") 
posts.where(posts[:hidden].eq(true).not).to_sql 
# => SELECT FROM `posts` WHERE NOT ((`posts`.`hidden` = 1)) 
+0

No es precisamente lo que estaba buscando, pero sigue siendo una muy buena respuesta. – Kostas

+0

¿Encontraste otra forma de hacer esto? Tal vez una mejor sintaxis? ¿La respuesta funcionó para ti? – Zabba

+0

En realidad, creo que ni siquiera es posible, ya que lo que en realidad estoy pidiendo es invertir y ActiveRecord :: Relation object que podría o no tener varias uniones e incluye lo que complicaría demasiado la cuestión (¿QUÉ PORCIONES deberíamos invertir y cuales no?) Creo que lo dejaré abierto hasta que me llegue una respuesta. – Kostas

5

Podemos tomar Zabba's answer aún más al pasar la consulta invertida de nuevo en ActiveRecord:

table = Post.arel_table 
query = table[:hidden].eq(true).not # the inverted query, still ARel 
Post.where(query) # plug it back into ActiveRecord 

Esto devolverá los objetos ActiveRecord, ya que normalmente se esperaría.

0

Lo que hago cuando estoy en busca de registros con una condición "no es cierto" (por ejemplo, falsa o nula) es:

Post.where(["(hidden IS NULL) OR (hidden = ?)", false]) 
-1

Para consultas de tabla individuales, esto funcionaría:

query = Post.where(hidden:true) 
inverse = Post.where('id not in (?)', query.pluck(:id)) 

Por supuesto, nos encontramos con problemas de eficiencia horribles, y no generaría la consulta SQL que está solicitando (aunque cuando se ejecute, eventualmente, producirá el mismo conjunto de resultados).

+0

En realidad, esto no sería tan malo si usa 'select' en lugar de' pluck' porque entonces anidaría la consulta en lugar de crear una matriz de Ruby de ids. – Ritchie

5

En los carriles 4, se not sufijo para este propósito:

Post.where.not(hidden: true).to_sql 
# => SELECT FROM `posts` WHERE `posts`.`hidden` != 1 

En los carriles 3 Puede utilizar squeel gem. Da muchas funciones útiles. Y con él puede escribir:

Post.where{ hidden != true }.to_sql 
# => SELECT FROM `posts` WHERE `posts`.`hidden` != 1 
Cuestiones relacionadas