Rails: Usando greater than / less than con una instrucción where


Estoy tratando de encontrar todos los Usuarios con un id mayor que 200, pero estoy teniendo algunos problemas con la sintaxis específica.

User.where(:id > 200) 

Y

User.where("? > 200", :id) 

Ambos fallaron.

Alguna sugerencia?

Author: Adam Templeton, 2012-07-03

7 answers

Prueba esto

User.where("id > ?", 200) 
 204
Author: RadBrad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-03 19:22:13

Solo he probado esto en Rails 4, pero hay una forma interesante de usar un rango con un hash where para obtener este comportamiento.

User.where(id: 201..Float::INFINITY)

Generará el SQL

SELECT `users`.* FROM `users`  WHERE (`users`.`id` >= 201)

Lo mismo se puede hacer por menos que con -Float::INFINITY.

Acabo de publicar una pregunta similar preguntando acerca de hacer esto con fechas aquí en SO.

>= vs >

Para evitar que la gente tenga que cavar a través y seguir la conversación de comentarios aquí están los destacar.

El método anterior solo genera una consulta >= y no a >. Hay muchas maneras de manejar esta alternativa.

Para números discretos

Puedes usar una estrategia number_you_want + 1 como la anterior, donde estoy interesado en Usuarios con id > 200 pero en realidad busco id >= 201. Esto está bien para enteros y números donde se puede incrementar por una sola unidad de interés.

Si tiene el número extraído en una constante bien nombrada, esto puede ser el más fácil de leer y entender de un vistazo.

Lógica invertida

Podemos usar el hecho de que x > y == !(x <= y) y usar la cadena donde no.

User.where.not(id: -Float::INFINITY..200)

Que genera el SQL

SELECT `users`.* FROM `users` WHERE (NOT (`users`.`id` <= 200))

Esto toma un segundo extra para leer y razonar, pero funcionará para valores o columnas no discretos donde no se puede usar la estrategia + 1.

Cuadro Arel

Si quieres ponerte elegante puedes hacer uso del Arel::Table.

User.where(User.arel_table[:id].gt(200))

Will generar el SQL

"SELECT `users`.* FROM `users` WHERE (`users`.`id` > 200)"

Los detalles son los siguientes:

User.arel_table              #=> an Arel::Table instance for the User model / users table
User.arel_table[:id]         #=> an Arel::Attributes::Attribute for the id column
User.arel_table[:id].gt(200) #=> an Arel::Nodes::GreaterThan which can be passed to `where`

Este enfoque le dará el exacto SQL que le interesa, sin embargo, no mucha gente usa la tabla Arel directamente y puede encontrarla desordenada y/o confusa. Usted y su equipo sabrán lo que es mejor para usted.

Bono

A partir de Rails 5 también puedes hacerlo con fechas!

User.where(created_at: 3.days.ago..DateTime::Infinity.new)

Generará el SQL

SELECT `users`.* FROM `users` WHERE (`users`.`created_at` >= '2018-07-07 17:00:51')

Doble Bonificación

Una vez que Ruby 2.6 es publicado (25 de diciembre de 2018) ¡podrás usar la nueva sintaxis de rango infinito! En lugar de 201..Float::INFINITY usted será capaz de escribir simplemente 201... Más información en esta entrada del blog.

 80
Author: Aaron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-10 17:05:41

Un mejor uso es crear un ámbito en el modelo user where(arel_table[:id].gt(id))

 21
Author: Mihai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-08 21:07:12

Si quieres una escritura más intuitiva, existe una gema llamada squeel que te permitirá escribir tus instrucciones de esta manera:

User.where{id > 200}

Observe que los caracteres' brace ' { } y id son solo un texto.

Todo lo que tienes que hacer es añadir squeel a tu Gemfile:

gem "squeel"

Esto podría facilitar mucho su vida al escribir una declaración SQL compleja en Ruby.

 4
Author: Douglas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-11 16:53:09

Arel es tu amigo.

User. where(User.arel_table[:id].gt (200))

 3
Author: joegiralt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-20 20:55:59

A menudo tengo este problema con los campos de fecha (donde los operadores de comparación son muy comunes).

Para profundizar en la respuesta de Mihai, que creo que es un enfoque sólido.

A los modelos puedes añadir ámbitos como este:

scope :updated_at_less_than, -> (date_param) { 
  where(arel_table[:updated_at].lt(date_param)) }

... y luego en su controlador, o donde sea que esté usando su modelo:

result = MyModel.updated_at_less_than('01/01/2017')

... un ejemplo más complejo con joins se ve así:

result = MyParentModel.joins(:my_model).
  merge(MyModel.updated_at_less_than('01/01/2017'))

Una gran ventaja de este enfoque es (a) que le permite componer sus consultas desde diferentes ámbitos y (b) evita colisiones de alias cuando se une a la misma tabla dos veces, ya que arel_table manejará esa parte de la generación de la consulta.

 1
Author: Brett Green,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-19 19:42:03

Más corto:

User.where("id > 200")
 -1
Author: Bengala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-09 00:48:42