2012-04-16 70 views
1

在Rails(3.2)的应用程序,我有这样一个模型类方法:如何将此原始SQL转换为Arel查询?

def import(level, max = 10) 
    db = ActiveRecord::Base.connection 
    result = db.execute("SELECT word FROM levels WHERE level == #{level} AND word NOT IN (SELECT entry FROM words) limit #{max};"); 

它只是在不为Word记录还不存在一个时间导入10个新词(创建10条记录) 。

架构看起来是这样的:

create_table "levels", :force => true do |t| 
    t.string "word" 
    t.integer "level" 
end 

create_table "words", :force => true do |t| 
    t.string "entry" 
    t.integer "level",  :default => 0 
    t.text "definition" 
    t.string "thesaurus", :default => "none" 
end 

我是SQL菜鸟。使用rails dbconsole(sqlite3,我在服务器上也使用sqlite3),我以某种方式想出了上面的原始sql查询。我有点知道我可以用Arel做同样的事情。我应该如何用ActiveRecord构造查询?

回答

1

以下(未测试)应该工作。它在子查询中使用pluck

Level.where(:level => level).where("word NOT IN (?)", Word.pluck(:entry)).limit(max) 
+0

谢谢!我明白了,但是'Level.where(“word not in?”,“apple,banana”)'产生:'SQLite3 :: SQLException:no such table:apple,banana:SELECT“levels”。* FROM“levels “在哪里(不是'苹果,香蕉'的单词)'嗯。 – knsmr 2012-04-16 10:14:06

+0

我想如果你在最后拿出'join(“,”)'它应该可以工作。 'IN'插值需要一个数组。 – tsherif 2012-04-16 10:18:20

+0

是的,我只是想出了自己。 (Level:> level).where(“word not IN(?)”,Word.pluck(:entry))。limit(max)'作品。你也需要'()'。非常感谢! – knsmr 2012-04-16 10:27:43

0

@ Gazler的解决方案看起来像它的工作原理,但我会用MetaWhere语法这是一个比较简洁的提供一种替代方案:

Level.where(:level => level, :word.not_in => Word.pluck(:entry)).limit(max) 
+0

美丽。但是,我得到这个错误:'NoMethodError:undefined method'not_in'for:word:Symbol'。这个not_in方法属于哪里? – knsmr 2012-04-16 10:36:45

+0

哦,我需要一个名为[MetaWhere]的宝石(http://erniemiller.org/projects/metawhere/)?它会在不久的将来登陆Rails吗?如果没有,我会坚持@Gazler的解决方案。不管怎么说,多谢拉! – knsmr 2012-04-16 10:42:19

+0

嗯......好笑。它似乎是内置于我使用的Rails版本(3.0.7)。如果它已经被取出,我必须小心... – tsherif 2012-04-16 10:56:34