Как совместить И и ИЛИ с помощью Sequel?

Я хочу сгенерировать SQL-запрос, подобный следующему, используя Ruby Sequel:

SELECT * FROM Objects WHERE (color = "red" AND shape = "triangle") OR 
                            (color = "blue" AND shape = "square") OR
                            (color = "green" AND shape = "circle")

Я хочу построить этот запрос программно из списка условий, чтобы я мог сделать что-то вроде этого:

conditions = [[[:color, "red"], [:shape, "triangle"]],
              [[:color, "blue"], [:shape, "square"]],
              [[:color, "green"], [:shape, "circle"]]]
DB[:Users].where(conditions.sql_or)

Он не обязательно должен следовать этой точной форме, но я хочу иметь возможность создавать условия программно, поэтому недостаточно иметь возможность построить этот запрос вручную.


person Ben P    schedule 23.10.2012    source источник
comment
Создайте SQL-запрос с помощью SQL... вы только что показали нам SQL-запрос. Можете уточнить ваши требования?   -  person Kermit    schedule 23.10.2012
comment
@njk Замените второй SQL на Ruby Sequel. Я применил правку.   -  person iain    schedule 23.10.2012


Ответы (2)


Попробуй это:

conditions = [ 
               {:color => "red", :shape => "triangle"},
               {:color => "blue", :shape => "square"},
               {:color => "green", :shape => "circle"}
             ]

head, *tail = *conditions

tail.inject(DB[:Users].filter(head)){|mem,obj| mem.or(obj) }

Я получил:

=> #<Sequel::Postgres::Dataset: "SELECT * FROM \"Users\" WHERE (((\"color\" = 'red') AND (\"shape\" = 'triangle')) OR ((\"color\" = 'blue') AND (\"shape\" = 'square')) OR ((\"color\" = 'green') AND (\"shape\" = 'circle')))">
person iain    schedule 23.10.2012
comment
+1. На минуту у меня заболела голова, потому что я никогда не думал об использовании inject в наборе данных Sequel, но потом это щелкнуло. Хорошо сделано. - person the Tin Man; 24.10.2012

Я думаю, что это вернет эквивалентный результат, используя другой запрос SQL:

DB[:Objects].where('(color, shape) in ?', conditions.sql_value_list).sql
=> "SELECT * FROM `Objects` WHERE ((color, shape) in (('red', 'triangle'), ('blue', 'square'), ('green', 'circle')))"

sql_value_list задокументировано в http://sequel.rubyforge.org/rdoc/classes/Array.html

В противном случае используйте:

objects = DB[:Objects].where(conditions[0])
conditions[1 .. -1].each { |c| objects = objects.or(c) }

Что приводит к:

SELECT * FROM `Objects` WHERE (((`color` = 'red') AND (`shape` = 'triangle')) OR ((`color` = 'blue') AND (`shape` = 'square')) OR ((`color` = 'green') AND (`shape` = 'circle')))

Я смотрел на ответ Иэна, и он в основном такой же, как мой второй, только более лаконичный; Мне нравится его элегантность.

person the Tin Man    schedule 23.10.2012