我从我的SQLite数据库中使用Ruby on Rails 2.3.5接收了一组模型。目前我正在使用子查询,以便只选择我真正想要的那些:
find(:all,
:conditions => "foo.id in (
SELECT bar.foo_id FROM bar
JOIN baz
ON baz.bar_id = bar.id
WHERE baz.bla in (1, 2, 3)
)"
)
我知道这是愚蠢的,因为子查询为每一行评估相同的结果,我猜SQLite不够聪明,不能注意到它可以被优化。所以我想把它从查询中删除。我知道我可以使用第二个find()
简单地从Rails调用它,但是鉴于子查询的返回值可能变得相对较大,我想在数据库中做所有事情,所以我不需要在数据库和Rails之间处理大量数据。
那么,我怎么能做模型的find()
并告诉它,它应该查找我的实际子查询的返回值,然后使用它的结果来比较我的其他行?我可以通过find()
的一次调用将其传递给SQLite吗?
答案 0 :(得分:0)
我想知道你是否可以做以下事情:
subs = connection.select_rows("SELECT bar.foo_id FROM bar
JOIN baz
ON baz.bar_id = bar.id
WHERE baz.bla in (1, 2, 3)")
find(:all, :conditions => "foo.id in (#{subs.join(',')})")
我试图在Rails 3中重写它。
答案 1 :(得分:0)
通常,您应该尝试在模型中定义关系。这样您就可以轻松使用ActiveRecord的助手
class Foo < ActiveRecord::Base
self.table_name = "foo"
has_many :bars
end
class Bar < ActiveRecord::Base
self.table_name = "bar"
belongs_to :foo
has_many :bazs
end
class Baz < ActiveRecord::Base
self.table_name = "baz"
belongs_to :bar
end
使用这些模型,您可以编写与此类似的查询:
Foo.find(:all, :include => {:bar => :baz}, :conditions => ["#{Baz.table_name}.id IN (?)", [1,2,3]])
答案 2 :(得分:0)
鉴于以下模型:
class Foo < ActiveRecord::Base
has_many :bars
has_many :bazs, :through => :bars
attr_accessible :title
end
class Bar < ActiveRecord::Base
belongs_to :foo
has_many :bazs
attr_accessible :title
end
class Baz < ActiveRecord::Base
belongs_to :bar
attr_accessible :title
end
你可以:
Foo.all(
:joins => { :bars => :bazs },
:conditions => { :bars => { :bazs => { :id => [1000] } } }
)
1000
是您感兴趣的Baz的ID。
这将生成以下SQL:
SELECT "foos".* FROM "foos" INNER JOIN "bars" ON "bars"."foo_id" = "foos"."id" INNER JOIN "bazs" ON "bazs"."bar_id" = "bars"."id" WHERE "bazs"."id" IN (1000)
如果你这样做,那是相同的:
Foo.all(
:joins => { :bars => :bazs },
:conditions => { :bazs => { :id => [1000] } }
)
甚至更好,使用through
关联:
Foo.all(
:joins => [:bazs],
:conditions => { :bazs => { :id => [1000] } }
)
结果将是符合该条件的所有Foo记录,并且SQL将是相同的。
希望能回答你的问题。