如何多次连接同一个表

时间:2011-11-23 01:41:34

标签: ruby-on-rails

我正在使用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 个答案:

答案 0 :(得分:6)

对于这些“非标准”查询,您最好的选择是直接转到Arel

这样的事情应该有效:

# 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,这是唯一的方法。

这有帮助吗?

答案 1 :(得分:-1)

 Select * from products where product_id 
 IN 
 (Select product_id  from custom_answers 
  where 
  text_value = 'bangle' 
  AND number_value<50)