2010-07-20 37 views
50

Tôi cần một câu lệnh SQL mà kiểm tra nếu một điều kiện được thỏa mãn:Ruby on Rails 3 howto make 'OR' tình trạng

SELECT * FROM my_table WHERE my_table.x=1 OR my_table.y=1 

Tôi muốn làm điều này 'Rails 3' chiều. Tôi đang tìm kiếm một cái gì đó như:

Account.where(:id => 1).or.where(:id => 2) 

Tôi biết rằng tôi luôn có thể dự phòng thành chuỗi sql hoặc chuỗi điều kiện. Tuy nhiên, theo kinh nghiệm của tôi, điều này thường dẫn đến hỗn loạn khi kết hợp phạm vi. Cách tốt nhất để làm việc này là gì?

Một câu hỏi khác có liên quan, là cách mô tả mối quan hệ phụ thuộc vào điều kiện OR. Cách duy nhất tôi tìm thấy:

has_many :my_thing, :class_name => "MyTable", :finder_sql => 'SELECT my_tables.* ' + 'FROM my_tables ' + 
'WHERE my_tables.payer_id = #{id} OR my_tables.payee_id = #{id}' 

Tuy nhiên, các lỗi này lại bị hỏng khi được sử dụng trong kết hợp. IS có cách nào tốt hơn để xác định điều này?

Trả lời

9

Đáng buồn thay, các .or là chưa được thực hiện (nhưng khi nó được, nó sẽ được TUYỆT).

Vì vậy, bạn sẽ phải làm một cái gì đó như:

class Project < ActiveRecord::Base 
    scope :sufficient_data, :conditions=>['ratio_story_completion != 0 OR ratio_differential != 0'] 
    scope :profitable, :conditions=>['profit > 0'] 

Bằng cách đó bạn vẫn có thể tuyệt vời và làm:

Project.sufficient_data.profitable 
+0

từ trang web arith github: Toán tử OR chưa được hỗ trợ. Nó sẽ hoạt động như sau: users.where (người dùng [: name] .eq ('bob') hoặc (người dùng [: age] .lt (25))) – hjuskewycz

6

Tôi muốn đi với IN khoản, ví dụ:

Account.where(["id in (?)", [1, 2]]) 
+0

Đó sẽ là thích hợp, nhưng nhận thấy tác giả là tìm kiếm @ 2 trường khác nhau ... – Brian

+0

Ồ đúng vậy, tôi đã viết câu trả lời dựa trên câu lệnh này 'Account.where (: id => 1) .or.where (: id => 2)'. Rõ ràng nó không hoạt động cho các trường khác nhau. – jpemberthy

+2

Sẽ không hoạt động nếu một trong các giá trị trong mảng là 'nil'. Giả sử bạn muốn tìm tất cả các bản ghi trong đó "đã xem" hoặc là 'false' hoặc' nil' và bạn làm 'Notification.where (: view => [false, nil])', nó sẽ không hoạt động, vì MySQL yêu cầu cú pháp 'đã xem = 0 HOẶC đã xem IS NULL' và * sẽ không hoạt động với *' đã xem = 0 HOẶC được xem = NULL' hoặc 'đã xem IN (0, NULL)'. –

71

chí này hoạt động trong Rails 5, xem rails master:

Post.where('id = 1').or(Post.where('id = 2')) 
# => SELECT * FROM posts WHERE (id = 1) OR (id = 2) 

Đối với Rails 3.0.4+:

accounts = Account.arel_table 
Account.where(accounts[:id].eq(1).or(accounts[:id].eq(2))) 
+12

Cú pháp này hoạt động. Có ai khác không thích nó? :) –

+4

Chắc chắn không thích cú pháp này. Tuy nhiên, tuy nhiên, thú vị. – DRobinson

+0

Tôi thích nó vì nó có thể được kết hợp – mdesantis

16

Các truy vấn arel này không thể đọc được đối với tôi.

Có gì sai với chuỗi SQL? Trong thực tế, Rails hướng dẫn cho thấy cách này là cách đầu tiên để tạo điều kiện trong các truy vấn: http://guides.rubyonrails.org/active_record_querying.html#array-conditions

Vì vậy, tôi đặt cược cho cách này để làm điều đó là "Rails cách":

Account.where("id = 1 OR id = 2") 

trong tôi ý kiến ​​khiêm tốn, ngắn hơn và rõ ràng hơn.

+7

Thích điều này, nhưng tôi sẽ sử dụng các giá trị được tham số hóa. 'Account.where (" id =? OR id =? ", 1,2)' – spyle

+0

Tôi không thấy bất kỳ lý do nào cho các giá trị được tham số khi sử dụng các số đơn giản. –

+0

Nếu bạn đang hardcoding id sau đó không có số đơn giản sẽ được tốt nhưng tôi sẽ nghi ngờ đây đang được trả lại từ nơi khác để paramterised là con đường để đi để tránh tiêm sql. –

5

Tôi đã sử dụng đá quý Squeel (https://github.com/ernie/squeel/) để thực hiện các truy vấn HOẶC và nó hoạt động đẹp mắt.

Nó cho phép bạn viết câu hỏi của bạn như Account.where{(id == 1) | (id == 2)}

4

Bạn có thể xác định một mảng như giá trị trong :conditions Hash.

Vì vậy, bạn có thể làm ví dụ:

Account.all(:conditions => { :id => [1, 2] }) 

Thử nghiệm với Rails 3.1.0

+1

điều này không hiệu quả vì bạn đang truy xuất tất cả các mục từ cơ sở dữ liệu và kiểm tra trong bộ nhớ –

111

Account.where(id: [1,2]) có lời giải thích cần thiết.

+0

Trình dọn dẹp sạch sẽ, khô nhất mà tôi từng thấy. Làm tốt lắm! –

+0

giải pháp tốt nhất mà tôi đã xem !!! Và nhìn rất nhiều (: –

+10

Điều này thật tuyệt vời và đơn giản. Tôi cũng đã học được rằng bạn có thể sử dụng 'nil' một cách an toàn: ví dụ: 'Thing.where (foo: [1, nil])' sẽ được dịch sang 'SELECT' những thứ ". * TỪ" những thứ "WHERE ((" những thứ "." foo "= 1 HOẶC" mọi thứ "." foo "IS NULL))'. Brilliant! –

2

thay thế cú pháp sử dụng Hash

Account.where("id = :val1 OR id = :val2", val1: 1, val2: 2). 

Điều này đặc biệt hữu ích, khi giá trị được so sánh với nhiều cột. ví dụ:

User.where("first_name = :name OR last_name = :name", name: 'tom') 
0

Với rails_or, bạn có thể làm điều đó thích:

Account.where(id: 1).or(id: 2) 

(. Nó hoạt động trong Rails 4 và 5, quá)