Próbuję znaleźć wszystkich użytkowników o identyfikatorze większym niż 200, ale mam problem z określoną składnią.
User.where(:id > 200)
i
User.where("? > 200", :id)
obaj zawiedli.
Jakieś sugestie?
Próbuję znaleźć wszystkich użytkowników o identyfikatorze większym niż 200, ale mam problem z określoną składnią.
User.where(:id > 200)
i
User.where("? > 200", :id)
obaj zawiedli.
Jakieś sugestie?
Odpowiedzi:
Spróbuj tego
User.where("id > ?", 200)
?
zamiast wstawiania 200
?
Testowałem to tylko w Railsach 4, ale jest ciekawy sposób na użycie zakresu z where
hashem, aby uzyskać takie zachowanie.
User.where(id: 201..Float::INFINITY)
wygeneruje SQL
SELECT `users`.* FROM `users` WHERE (`users`.`id` >= 201)
To samo można zrobić za mniej niż za pomocą -Float::INFINITY
.
Właśnie opublikowałem podobne pytanie z pytaniem o zrobienie tego z datami tutaj na SO .
>=
vs >
Aby ludzie nie musieli przekopywać się i śledzić rozmowy z komentarzami, oto najważniejsze informacje.
Powyższa metoda generuje tylko >=
zapytanie, a nie plik >
. Istnieje wiele sposobów radzenia sobie z tą alternatywą.
Dla liczb dyskretnych
Możesz użyć number_you_want + 1
strategii takiej jak powyżej, w której jestem zainteresowany użytkownikami, id > 200
ale faktycznie ich szukam id >= 201
. Jest to dobre w przypadku liczb całkowitych i liczb, w przypadku których można zwiększyć o jedną jednostkę zainteresowania.
Jeśli masz wyodrębnioną liczbę do dobrze nazwanej stałej, może to być najłatwiejsze do odczytania i zrozumienia na pierwszy rzut oka.
Logika odwrócona
Możemy wykorzystać fakt, że x > y == !(x <= y)
i użyć łańcucha gdzie nie.
User.where.not(id: -Float::INFINITY..200)
który generuje SQL
SELECT `users`.* FROM `users` WHERE (NOT (`users`.`id` <= 200))
Przeczytanie i uzasadnienie zajmie dodatkową sekundę, ale będzie działać dla wartości niedyskretnych lub kolumn, w których nie można użyć + 1
strategii.
Stół Arel
Jeśli chcesz uzyskać fantazję, możesz skorzystać z Arel::Table
.
User.where(User.arel_table[:id].gt(200))
wygeneruje SQL
"SELECT `users`.* FROM `users` WHERE (`users`.`id` > 200)"
Szczegóły są następujące:
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`
To podejście pozwoli Ci uzyskać dokładnie ten SQL, który Cię interesuje, jednak niewiele osób używa bezpośrednio tabeli Arel i może uznać ją za nieporządną i / lub mylącą. Ty i Twój zespół będziecie wiedzieć, co jest dla Ciebie najlepsze.
Począwszy od Rails 5 możesz to również zrobić z datami!
User.where(created_at: 3.days.ago..DateTime::Infinity.new)
wygeneruje SQL
SELECT `users`.* FROM `users` WHERE (`users`.`created_at` >= '2018-07-07 17:00:51')
Po wydaniu Ruby 2.6 (25 grudnia 2018 r.) Będziesz mógł używać nowej składni nieskończonego zakresu! Zamiast tego 201..Float::INFINITY
będziesz mógł po prostu pisać 201..
. Więcej informacji w tym poście na blogu .
where
dopasowań. Bo >
proponuję użyć >= (number_you_want + 1)
dla uproszczenia. Jeśli naprawdę chcesz mieć pewność, że jest to tylko >
zapytanie, możesz uzyskać dostęp do tabeli ARel. Każda klasa dziedzicząca po ActiveRecord
ma arel_table
metodę pobierającą, która zwraca wartość Arel::Table
dla tej klasy. Dostęp do kolumn w tabeli uzyskuje się za pomocą []
metody User.arel_table[:id]
. W ten sposób Arel::Attributes::Attribute
możesz zadzwonić gt
i przekazać 200
. Można to następnie przekazać where
. np 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>)
(wsteczne tiki wokół nazw tabel i kolumn pominięte przy formatowaniu komentarzy SO).
Jeśli chcesz bardziej intuicyjnego pisania, istnieje klejnot zwany squeel , który pozwoli ci napisać instrukcje w następujący sposób:
User.where{id > 200}
Zwróć uwagę na znaki „nawiasów klamrowych” {} i id
będące tylko tekstem.
Wszystko, co musisz zrobić, to dodać squeel do swojego Gemfile:
gem "squeel"
Może to znacznie ułatwić życie podczas pisania złożonych instrukcji SQL w języku Ruby.
Inną ciekawą możliwością jest ...
User.where("id > :id", id: 100)
Ta funkcja pozwala tworzyć bardziej zrozumiałe zapytania, jeśli chcesz zamienić w wielu miejscach, na przykład ...
User.where("id > :id OR number > :number AND employee_id = :employee", id: 100, number: 102, employee: 1205)
Ma to większe znaczenie niż dużo ?
w zapytaniu ...
User.where("id > ? OR number > ? AND employee_id = ?", 100, 102, 1205)
Często mam ten problem z polami dat (gdzie operatory porównania są bardzo powszechne).
Aby rozwinąć dalej odpowiedź Mihai, która moim zdaniem jest solidnym podejściem.
Do modeli możesz dodać takie zakresy:
scope :updated_at_less_than, -> (date_param) {
where(arel_table[:updated_at].lt(date_param)) }
... a następnie w kontrolerze lub gdziekolwiek używasz swojego modelu:
result = MyModel.updated_at_less_than('01/01/2017')
... bardziej złożony przykład z łączeniami wygląda następująco:
result = MyParentModel.joins(:my_model).
merge(MyModel.updated_at_less_than('01/01/2017'))
Ogromną zaletą tego podejścia jest (a) możliwość komponowania zapytań z różnych zakresów oraz (b) uniknięcie kolizji aliasów przy dwukrotnym dołączaniu do tej samej tabeli, ponieważ arel_table będzie obsługiwać tę część generowania zapytania.
Railsy 6.1 dodały nową „składnię” dla operatorów porównania w where
warunkach, na przykład:
Post.where('id >': 9)
Post.where('id >=': 9)
Post.where('id <': 3)
Post.where('id <=': 3)
Twoje zapytanie można więc przepisać w następujący sposób:
User.where('id >': 200)
Oto link do PR, gdzie można znaleźć więcej przykładów.
Krótszy:
User.where("id > 200")
where("id > ?", 200)
składnia). To nie pozwala na osiągnięcie tego.