2010-07-20 4 views
50

Мне нужно заявление SQL, что проверить, если один условие:Рубин на Rails 3 Howto марки «ИЛИ» условие

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

Я хочу сделать это «Rails 3» путь. Я искал что-то вроде:

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

Я знаю, что всегда могу откинуться на sql или строку условий. Однако, по моему опыту, это часто приводит к хаосу при объединении областей. Каков наилучший способ сделать это?

Другой связанный с этим вопрос, как определить отношения, которые зависят от условия ИЛИ. Единственный способ, который я нашел:

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}' 

Однако они снова ломаются при использовании в комбинациях. Есть ли лучший способ указать это?

ответ

9

К сожалению, .Или еще не реализован (но когда она есть, это будет УДИВИТЕЛЬНЫМ).

Таким образом, вы должны сделать что-то вроде:

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

Таким образом, вы все еще может быть удивительным и сделать:

Project.sufficient_data.profitable 
+0

с сайта isl github: Оператор OR еще не поддерживается. Он будет работать следующим образом: users.where (users [: name] .eq ('bob'). Или (users [: age] .lt (25))) – hjuskewycz

6

Я бы с IN пунктом, например:

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

Это было бы уместно, но обратите внимание, автор looking @ 2 разных полей ... – Brian

+0

О да, это правда, я написал ответ, основанный на этом выражении 'Account.where (: id => 1) .or.where (: id => 2)'. Очевидно, что это не работает для разных полей. – jpemberthy

+2

Не будет работать, если одно из значений в массиве - 'nil'. Скажем, вы хотите найти все записи, где «просматривается» либо «false», либо «nil», а вы «Notification.where (: просмотрено => [false, nil])», это не сработает, так как MySQL требует синтаксис 'посмотрел = 0 или просмотрел IS NULL' и * не будет работать с *' просмотрен = 0 или просмотрено = NULL' или 'просмотрено IN (0, NULL)'. –

71

Это будет работать в Rails 5 см rails master:

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

Для Rails 3.0.4+:

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

Этот синтаксис работает. Кто-нибудь еще не нравится? :) –

+4

Определенно не нравится этот синтаксис. Тем не менее, интересно. – DRobinson

+0

Мне нравится, потому что он может быть комбинационным – mdesantis

16

Эти запросы isl не читаются для меня.

Что случилось с строкой SQL? В самом деле, Rails Guides выставляет так как первый способ сделать условия в запросах: http://guides.rubyonrails.org/active_record_querying.html#array-conditions

Итак, я уверен, на этом пути, чтобы сделать это как «Rails путь»:

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

В моей скромное мнение, оно короче и яснее.

+7

Предпочитаю это, но я бы использовал параметризованные значения. 'Account.where (" id =? OR id =? ", 1,2)' – spyle

+0

Я не вижу причин для параметризованных значений при использовании простых чисел. –

+0

Если вы жестко кодируете идентификатор, тогда никакие простые номера не будут хорошими, но я бы заподозрил, что они возвращаются из других источников, так что парамизация - это способ избежать внедрения sql. –

5

Я использовал камень Squeel (https://github.com/ernie/squeel/), чтобы делать или запросы, и он работает красиво.

Это позволяет написать запрос в Account.where{(id == 1) | (id == 2)}

4

Вы можете определить массив в качестве значения в :conditions Hash.

Таким образом, вы могли бы сделать, например:

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

Испытано с Rails 3.1.0

+1

Это неэффективно, потому что вы извлекаете все элементы из базы данных и проверяете в памяти –

111

Account.where(id: [1,2]) никакого объяснения необходимости.

+0

Самый чистый, самый DRYest, который я видел. Отличная работа! –

+0

лучшее решение, которое я видел !!! И выглядел много (: –

+10

Это замечательно и так просто. Я также узнал, что вы можете безопасно использовать «nil»: например, 'Thing.where (foo: [1, nil])' будет переведен в 'SELECT ' вещи ». * FROM« вещи »WHERE ((« вещи ».« foo »= 1 ИЛИ« вещи ».« foo »IS NULL))'. Brilliant! –

2

Альтернативный синтаксис с использованием хэш-

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

Это особенно полезно, когда значение сравнивается с несколькими столбцами. например:

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

С rails_or, вы могли бы сделать это нравится:

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

(. Он работает в Rails 4 и 5, тоже)

Смежные вопросы