Estou tentando encontrar todos os usuários com um ID maior que 200, mas estou tendo problemas com a sintaxe específica.
User.where(:id > 200)
e
User.where("? > 200", :id)
ambos falharam.
Alguma sugestão?
Estou tentando encontrar todos os usuários com um ID maior que 200, mas estou tendo problemas com a sintaxe específica.
User.where(:id > 200)
e
User.where("? > 200", :id)
ambos falharam.
Alguma sugestão?
Respostas:
Tente isto
User.where("id > ?", 200)
?
, em vez de incluir o 200
?
Eu só testei isso no Rails 4, mas há uma maneira interessante de usar um intervalo com um where
hash para obter esse comportamento.
User.where(id: 201..Float::INFINITY)
irá gerar o SQL
SELECT `users`.* FROM `users` WHERE (`users`.`id` >= 201)
O mesmo pode ser feito por menos do que com -Float::INFINITY
.
Acabei de postar uma pergunta semelhante sobre como fazer isso com datas aqui no SO .
>=
vs >
Para evitar que as pessoas tenham que pesquisar e acompanhar a conversa de comentários, aqui estão os destaques.
O método acima gera apenas uma >=
consulta e não a >
. Existem muitas maneiras de lidar com essa alternativa.
Para números discretos
Você pode usar uma number_you_want + 1
estratégia como a acima, onde me interesso por usuários, id > 200
mas na verdade procuro id >= 201
. Isso é bom para números inteiros e números em que você pode incrementar por uma única unidade de interesse.
Se você tiver o número extraído em uma constante bem nomeada, isso pode ser o mais fácil de ler e entender rapidamente.
Lógica invertida
Podemos usar o fato de que x > y == !(x <= y)
e usar a cadeia where not.
User.where.not(id: -Float::INFINITY..200)
que gera o SQL
SELECT `users`.* FROM `users` WHERE (NOT (`users`.`id` <= 200))
Isso leva um segundo extra para ler e refletir, mas funcionará para valores ou colunas não discretos, nos quais você não pode usar a + 1
estratégia.
Mesa Arel
Se você quiser se divertir, pode usar o Arel::Table
.
User.where(User.arel_table[:id].gt(200))
irá gerar o SQL
"SELECT `users`.* FROM `users` WHERE (`users`.`id` > 200)"
Os detalhes são os seguintes:
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`
Essa abordagem fornece o SQL exato em que você está interessado, mas poucas pessoas usam a tabela Arel diretamente e podem achar que é confusa e / ou confusa. Você e sua equipe saberão o que é melhor para você.
A partir do Rails 5, você também pode fazer isso com datas!
User.where(created_at: 3.days.ago..DateTime::Infinity.new)
irá gerar o SQL
SELECT `users`.* FROM `users` WHERE (`users`.`created_at` >= '2018-07-07 17:00:51')
Depois que o Ruby 2.6 for lançado (25 de dezembro de 2018), você poderá usar a nova sintaxe de alcance infinito! Em vez de 201..Float::INFINITY
você será capaz de escrever 201..
. Mais informações nesta postagem do blog .
where
fósforos básicos . Pois >
eu sugiro usar um >= (number_you_want + 1)
para simplicidade. Se você realmente deseja garantir que seja apenas uma >
consulta, pode acessar a tabela ARel. Toda classe que herda de ActiveRecord
possui um arel_table
método getter que retorna o valor Arel::Table
dessa classe. As colunas na tabela são acessadas com o []
método like User.arel_table[:id]
. Isso retorna e Arel::Attributes::Attribute
você pode ligar gt
e transmitir 200
. Isso pode ser passado para where
. por exemplo User.where(User.arel_table[:id].gt(200))
.
User.where(created_at: 3.days.ago..DateTime::Infinity.new)
.
WHERE (users.created_at >= '2016-04-09 14:31:15' AND users.created_at < #<Date::Infinity:0x00>)
(marcações em volta dos nomes de tabelas e colunas omitidos para formatação de comentários de SO).
Se você deseja uma escrita mais intuitiva, existe uma gema chamada squeel que permitirá que você escreva suas instruções assim:
User.where{id > 200}
Observe os caracteres 'chave' {} e id
sendo apenas um texto.
Tudo o que você precisa fazer é adicionar um squeel ao seu Gemfile:
gem "squeel"
Isso pode facilitar muito sua vida ao escrever instruções SQL complexas em Ruby.
Outra possibilidade chique é ...
User.where("id > :id", id: 100)
Esse recurso permite criar consultas mais compreensíveis se você deseja substituir em vários locais, por exemplo ...
User.where("id > :id OR number > :number AND employee_id = :employee", id: 100, number: 102, employee: 1205)
Isso tem mais significado do que ter muito ?
na consulta ...
User.where("id > ? OR number > ? AND employee_id = ?", 100, 102, 1205)
Muitas vezes tenho esse problema com os campos de data (onde os operadores de comparação são muito comuns).
Para aprofundar a resposta de Mihai, que acredito ser uma abordagem sólida.
Para os modelos, você pode adicionar escopos como este:
scope :updated_at_less_than, -> (date_param) {
where(arel_table[:updated_at].lt(date_param)) }
... e depois no seu controlador, ou onde quer que você esteja usando o seu modelo:
result = MyModel.updated_at_less_than('01/01/2017')
... um exemplo mais complexo com junções se parece com isso:
result = MyParentModel.joins(:my_model).
merge(MyModel.updated_at_less_than('01/01/2017'))
Uma grande vantagem dessa abordagem é (a) permitir compor suas consultas de diferentes escopos e (b) evitar colisões de alias quando você ingressar na mesma tabela duas vezes, já que o arel_table tratará essa parte da geração de consultas.
O Rails 6.1 adicionou uma nova 'sintaxe' para operadores de comparação em where
condições, por exemplo:
Post.where('id >': 9)
Post.where('id >=': 9)
Post.where('id <': 3)
Post.where('id <=': 3)
Portanto, sua consulta pode ser reescrita da seguinte maneira:
User.where('id >': 200)
Aqui está um link para o PR, onde você pode encontrar mais exemplos.
Mais curta:
User.where("id > 200")
where("id > ?", 200)
sintaxe). Isso não consegue isso.