与ActiveRecord的负面比较

时间:2015-06-03 18:45:12

标签: sql ruby-on-rails activerecord

我有两张桌子:

sales

period_id
customer_id
product_id
value

total_sales

period_id
customer_id
product_id
value

我想选择period_id上存在的customer_idsales的所有组合,但不会total_sales上存在。{1}}。我相信这是一个简短的方法。但我认为每种方法都涉及N + 1个查询。

我该怎么做?

2 个答案:

答案 0 :(得分:0)

在我看来,正是这种情况下,与纯粹的ActiveRecord方法不同并将一些SQL引入表中是合理的。这应该很好地完成这个技巧:

Sale.find_by_sql("
   SELECT * FROM sales WHERE NOT EXISTS (
      SELECT 1 FROM total_sales 
                WHERE total_sales.period_id = sales.period_id AND 
                      total_sales.customer_id = sales.customer_id)
")

我想它也可以用更多的ActiveRecordish风格完成,但它肯定会失去代码的清晰度。

当然,如果你把它放到你的代码库中,你真的应该将它包装在一个方法中并留在模型中,这样SQL代码至少不会流入控制器。

希望这有帮助!

P.S。哦,这是我用来测试它的SQL小提琴:http://sqlfiddle.com/#!15/eaf1d/1

答案 1 :(得分:0)

如何首先获得匹配的列表,然后使用它来获取您真正想要的行:

    unwanted_ids = Sale.joins('inner join total_sales on sales.period_id = total_sales.period_id and sales.customer_id = total_sales.customer_id').pluck('distinct sales.id')
    wanted_rows = unwanted_ids.any? Sale.where('id not in (?)', unwanted_ids) : Sale.all
    wanted_rows.select(:period_id, :customer_id) #if you only want these two

这样您只需要两个查询。

编辑:

你也可以这样做:

    Sale.joins('left outer join total_sales on sales.period_id = total_sales.period_id and sales.customer_id = total_sales.customer_id').where('total_sales.period_id is null')

是否在一个查询中