Tôi đang cố gắng tìm tất cả Người dùng có id lớn hơn 200, nhưng tôi gặp một số rắc rối với cú pháp cụ thể.
User.where(:id > 200)
và
User.where("? > 200", :id)
đều thất bại
Bất kỳ đề xuất?
Tôi đang cố gắng tìm tất cả Người dùng có id lớn hơn 200, nhưng tôi gặp một số rắc rối với cú pháp cụ thể.
User.where(:id > 200)
và
User.where("? > 200", :id)
đều thất bại
Bất kỳ đề xuất?
Câu trả lời:
Thử cái này
User.where("id > ?", 200)
?
, hơn là nội tuyến 200
?
Tôi chỉ thử nghiệm điều này trong Rails 4 nhưng có một cách thú vị để sử dụng phạm vi có where
hàm băm để thực hiện hành vi này.
User.where(id: 201..Float::INFINITY)
sẽ tạo SQL
SELECT `users`.* FROM `users` WHERE (`users`.`id` >= 201)
Điều tương tự có thể được thực hiện cho ít hơn với -Float::INFINITY
.
Tôi vừa đăng một câu hỏi tương tự hỏi về việc làm này với ngày ở đây trên SO .
>=
đấu với >
Để tránh mọi người phải tìm hiểu kỹ và theo dõi cuộc trò chuyện bình luận ở đây là những điểm nổi bật.
Phương pháp trên chỉ tạo ra một >=
truy vấn chứ không phải a >
. Có nhiều cách để xử lý sự thay thế này.
Đối với số rời rạc
Bạn có thể sử dụng một number_you_want + 1
chiến lược như ở trên nơi tôi quan tâm đến Người dùng id > 200
nhưng thực sự tìm kiếm id >= 201
. Điều này tốt cho số nguyên và số mà bạn có thể tăng theo một đơn vị quan tâm.
Nếu bạn có số được trích xuất thành một hằng số có tên tốt thì đây có thể là thứ dễ đọc và dễ hiểu nhất trong nháy mắt.
Logic đảo ngược
Chúng ta có thể sử dụng thực tế đó x > y == !(x <= y)
và sử dụng chuỗi không phải chuỗi.
User.where.not(id: -Float::INFINITY..200)
tạo ra SQL
SELECT `users`.* FROM `users` WHERE (NOT (`users`.`id` <= 200))
Việc này cần thêm một giây để đọc và suy luận về nhưng sẽ hoạt động đối với các giá trị hoặc cột không rời rạc mà bạn không thể sử dụng + 1
chiến lược.
Bàn Arel
Nếu bạn muốn có được ưa thích, bạn có thể sử dụng Arel::Table
.
User.where(User.arel_table[:id].gt(200))
sẽ tạo SQL
"SELECT `users`.* FROM `users` WHERE (`users`.`id` > 200)"
Các chi tiết cụ thể như sau:
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`
Cách tiếp cận này sẽ giúp bạn có được SQL chính xác mà bạn quan tâm, tuy nhiên không nhiều người sử dụng bảng Arel trực tiếp và có thể thấy nó lộn xộn và / hoặc khó hiểu. Bạn và nhóm của bạn sẽ biết những gì tốt nhất cho bạn.
Bắt đầu trong Rails 5, bạn cũng có thể làm điều này với ngày!
User.where(created_at: 3.days.ago..DateTime::Infinity.new)
sẽ tạo SQL
SELECT `users`.* FROM `users` WHERE (`users`.`created_at` >= '2018-07-07 17:00:51')
Khi Ruby 2.6 được phát hành (ngày 25 tháng 12 năm 2018), bạn sẽ có thể sử dụng cú pháp phạm vi vô hạn mới! Thay vì 201..Float::INFINITY
bạn sẽ chỉ có thể viết 201..
. Thêm thông tin trong bài viết blog này .
where
. Đối với >
tôi đề nghị sử dụng một >= (number_you_want + 1)
cho đơn giản. Nếu bạn thực sự muốn đảm bảo nó chỉ là một >
truy vấn, bạn có thể truy cập vào bảng ARel. Mỗi lớp kế thừa từ ActiveRecord
có một arel_table
phương thức getter trả về Arel::Table
cho lớp đó. Các cột trên bảng được truy cập với []
phương thức như thế nào User.arel_table[:id]
. Điều này trả về một Arel::Attributes::Attribute
bạn có thể gọi gt
và chuyển vào 200
. Điều này có thể được chuyển đến where
. ví dụ 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>)
(đánh dấu ngược xung quanh tên bảng và tên cột được bỏ qua cho định dạng nhận xét SO).
Nếu bạn muốn viết một cách trực quan hơn, nó tồn tại một viên ngọc gọi là squeel cho phép bạn viết hướng dẫn của bạn như thế này:
User.where{id > 200}
Lưu ý các ký tự 'cú đúp' {} và id
chỉ là một văn bản.
Tất cả những gì bạn phải làm là thêm squeel vào Gemfile của mình:
gem "squeel"
Điều này có thể giảm bớt cuộc sống của bạn rất nhiều khi viết câu lệnh SQL phức tạp trong Ruby.
Một khả năng thú vị khác là ...
User.where("id > :id", id: 100)
Tính năng này cho phép bạn tạo các truy vấn dễ hiểu hơn nếu bạn muốn thay thế ở nhiều nơi, ví dụ ...
User.where("id > :id OR number > :number AND employee_id = :employee", id: 100, number: 102, employee: 1205)
Điều này có nhiều ý nghĩa hơn là có rất nhiều ?
truy vấn ...
User.where("id > ? OR number > ? AND employee_id = ?", 100, 102, 1205)
Tôi thường gặp vấn đề này với các trường ngày (trong đó các toán tử so sánh rất phổ biến).
Để giải thích thêm về câu trả lời của Mihai, mà tôi tin là một cách tiếp cận vững chắc.
Để các mô hình, bạn có thể thêm phạm vi như thế này:
scope :updated_at_less_than, -> (date_param) {
where(arel_table[:updated_at].lt(date_param)) }
... Và sau đó trong bộ điều khiển của bạn hoặc bất cứ nơi nào bạn đang sử dụng mô hình của mình:
result = MyModel.updated_at_less_than('01/01/2017')
... một ví dụ phức tạp hơn với các phép nối trông như thế này:
result = MyParentModel.joins(:my_model).
merge(MyModel.updated_at_less_than('01/01/2017'))
Một lợi thế lớn của phương pháp này là (a) nó cho phép bạn soạn các truy vấn của mình từ các phạm vi khác nhau và (b) tránh va chạm bí danh khi bạn tham gia vào cùng một bảng hai lần vì arel_table sẽ xử lý phần đó của việc tạo truy vấn.
Rails 6.1 đã thêm một 'cú pháp' mới cho các toán tử so sánh trong các where
điều kiện, ví dụ:
Post.where('id >': 9)
Post.where('id >=': 9)
Post.where('id <': 3)
Post.where('id <=': 3)
Vì vậy, truy vấn của bạn có thể được viết lại như sau:
User.where('id >': 200)
Đây là một liên kết đến PR nơi bạn có thể tìm thấy nhiều ví dụ.
Ngắn hơn:
User.where("id > 200")
where("id > ?", 200)
cú pháp) được tham số hóa . Điều này không đạt được điều đó.