使用Rails 4 Activerecord将多个列计数合并到单个查询中

时间:2014-12-15 22:33:57

标签: ruby-on-rails postgresql rails-activerecord

Rails 4.1,Postgres 9.3,部署到Heroku

我正在尝试减少对数据库的调用次数。

我有一个大表,调查,有多个布尔列,如role_composerrole_performer,等等。

控制器有多个查询,例如

@sample = Survey.where(...whatever...)
@Composers = @sample.count("case when role_composer then true end")
...
@Performers = @sample.count("case when role_performer then true end")

这样可以正常工作,但会导致对数据库的许多单独查询只有select中的表达式不同。有没有办法将此构造为具有多个聚合/计算列的一个查询?我也有使用average()和表达式的查询,但最常见的是count()。

在postgres中,这有效:

SELECT count(case when role_composer then true end) as "COMPOSERS", count(case when role_performer then true end) as "PERFORMERS" from surveys;

使用@sample上的Activerecord方法而不是求助于find_by_sql()的任何方法吗?

我尝试了多种方法但没有成功:.count().count().count([array]).select("count(...) as col1, count(...) as col2").select(["count(...) as col1", "count(...) as col2"])

提前感谢您的任何答案。

1 个答案:

答案 0 :(得分:2)

如果你记得两件事,你的.select("count(...) as col1, count(...) as col2")版本应该可以正常工作:

    即使查询只返回一行,
  1. M.where(...).select(...)也会返回多个内容。
  2. 仅仅因为inspect输出中没有出现某些内容并不意味着它不存在。
  3. 您正在进行没有GROUP BY的聚合,因此您只能获得一行。要打开该行,您可以说first

    counts = Survey.where(...)
                   .select('count(case when role_composer then true end) as composers,  count(case when role_performer then true end) as performers')
                   .first
    

    这会在Survey中为您提供counts个实例。如果你在控制台中查看counts,你会看到如下内容:

    #<Survey > 
    

    inspect输出仅包含列中的值(即Survey类知道的内容),但composersperformers将在那里。但是,由于ActiveRecord不知道它们应该是什么类型,它们将作为字符串出现:

    composers  = counts.composers.to_i
    performers = counts.performers.to_i
    

    如果去寻找,select中的所有内容都会存在。