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?
7 answers
Prueba esto
User.where("id > ?", 200)
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.
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))
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.
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))
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.
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")
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