Как присоединиться к одному и тому же столу более одного раза - PullRequest
0 голосов
/ 23 ноября 2011

Я использую postgresql.

У меня есть таблица с именем custom_field_answers. Данные выглядят так:

Id | product_id | value      | number_value | 
4  | 2          |            | 117          |
3  | 1          |            | 107          |
2  | 1          | bangle     |              |
1  | 2          | necklace   |              |

Я хочу найти все продукты, у которых text_value равно 'bangle' и number_value меньше 50.

SELECT p.*
FROM "products" AS p
INNER JOIN "custom_field_answers" AS a1 ON p."id" = a1."product_id"
INNER JOIN "custom_field_answers" AS a2 ON p."id" = a1."product_id" 
WHERE a1."value" = 'bangle' AND a2."number_value" < 50

Я пытался создать этот sql со следующим кодом.

conditions = <conditions from arel>
relation = self.scoped
conditions.each do |condition|
  relation = relation.merge(where(condition))
end
joins(:custom_field_answers).merge(relation)
relation.to_a

Это производит следующий sql

SELECT "products".* FROM "products" INNER JOIN "custom_field_answers" 
ON "custom_field_answers"."product_id" = "products"."id" 
WHERE ("custom_field_answers"."value" ILIKE 'bangle') 
AND ("custom_field_answers"."number_value" < 50)

Как вы можете видеть, этот sql не похож на нужный sql (упомянутый вверху).

Я попытался немного переместить код соединения

relation = self.scoped
conditions.each do |condition|
  relation = relation.merge(where(condition).joins(:custom_field_answers))
end
relation.to_a

Все еще не повезло.

Любой знает, как форсировать новое соединение для каждого отношения. Я использую Rails 3.1.1.

Ответы [ 2 ]

6 голосов
/ 23 ноября 2011

Лучшей ставкой для «нестандартных» запросов, таких как эти, было бы пойти прямо к Арел .

Примерно так должно работать:

# in your model
p  = Arel::Table.new(:products, :as => 'p')
a1 = Arel::Table.new(:custom_field_answers, :as => 'a1')
a2 = Arel::Table.new(:custom_field_answers, :as => 'a2')

relation = p.
  project(Arel.sql('*')).
  join(a1).on(p[:id].eq(a1[:product_id])).
  join(a2).on(p[:id].eq(a2[:product_id]))

relation = relation.where(a1[:value].eq('bangle')).where(a2[:number_value].lt(50))

relation.to_sql #should return the SQL you're after

Не так хорошо, как Rails Arel Wrapper, но для сложных запросов это единственный способ, если вы не хотите переходить к сырому SQL в своем коде.

Помогает ли это?

0 голосов
/ 23 ноября 2011
 Select * from products where product_id 
 IN 
 (Select product_id  from custom_answers 
  where 
  text_value = 'bangle' 
  AND number_value<50)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...