在Active Admin仪表板(Rails,Active admin 1.0,Postgresql数据库,postgres_ext gem)中计算序列化属性(数组)中值的出现次数

时间:2013-12-21 14:46:03

标签: ruby-on-rails arrays ruby-on-rails-3 postgresql activeadmin

我希望有一个基本表,总结数组中值的出现次数。

我的应用程序是一个每日交易应用程序,旨在了解更多Ruby on Rails。

我有一个模特交易,它有一个名为Deal_goal的属性。它是一个多重选择,在数组中序列化。

以下是来自schema.db的deal_goal:

t.string   "deal_goal",:array => true

enter image description here

所以交易A可以有交易=目标= [交通,资格]和另一笔交易可以作为deal_goal = [品牌,交通,收购]

我想要构建的是我的仪表板中的一个表格,它将采用每种类型的目标(数组中的每个值)并计算其deal_goal的数组将包含此类目标并计算它们的交易数量。

我的目标是拥有这张表:

enter image description here

我怎样才能做到这一点?我想我需要为每种类型的值对每个deal_goal数组进行分组,然后计算这些目标在数组中出现的次数。我对RoR很陌生,无法做到这一点。

到目前为止,这是我的代码:

column do
    panel "top of Goals" do
          table_for Deal.limit(10) do
            column ("Goal"),  :deal_goal ????
            # add 2 columns:
            'nb of deals with this goal'
            'Share of deals with this goal'
          end
        end

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

我想不出任何干净的方式来获得你通过ActiveRecord获得的结果,但在SQL中它很容易。

你真正要做的就是打开deal_goal数组并根据打开的数组构建直方图。您可以这样直接在SQL中表达:

with expanded_deals(id, goal) as (
    select id, unnest(deal_goal)
    from deals
)
select goal, count(*) n
from expanded_deals
group by goal

如果你想要包含所有四个目标,即使它们没有出现在任何deal_goal中,那么只需要左下角加入即可:

with
    all_goals(goal) as (
        values ('traffic'),
               ('acquisition'),
               ('branding'),
               ('qualification')
    ),
    expanded_deals(id, goal) as (
        select id, unnest(deal_goal)
        from deals
    )
select all_goals.goal goal,
       count(expanded_deals.id) n
from all_goals
left join expanded_deals using (goal)
group by all_goals.goal

SQL演示http://sqlfiddle.com/#!15/3f0af/20

将其中一个投入select_rows来电,您将获得数据:

Deal.connection.select_rows(%q{ SQL goes here }).each do |row|
  goal = row.first
  n    = row.last.to_i
  #....
end

这里可能有很多你不熟悉的事情,所以我会解释一下。

首先,我使用WITH和公用表表达式(CTE)来简化SELECT。 WITH is a standard SQL feature,允许您生成SQL宏或内联的临时表。在大多数情况下,您可以将CTE放在查询中,其名称为:

with some_cte(colname1, colname2, ...) as ( some_pile_of_complexity )
select * from some_cte

是这样的:

select * from ( some_pile_of_complexity ) as some_cte(colname1, colname2, ...)

CTE是将过于复杂的查询/方法重构为更小且更易于理解的SQL的方法。

unnest是一个数组函数,它将数组解包为单个行。因此,如果您说unnest(ARRAY[1,2]),则会返回两行:12

PostgreSQL中的

VALUES或多或少地用于生成内联常量表。您可以在任何可以使用普通表的地方使用VALUES,它不仅仅是您在INSERT中抛出的一些语法,以告诉数据库要插入哪些值。这意味着你可以这样说:

select * from (values (1), (2)) as dt

并获取行12。将VALUES投入到CTE中会使事情变得美观和可读,并使其看起来像最终查询中的任何旧表。