Não consigo pensar em nenhuma maneira limpa de obter os resultados que você procura por meio do ActiveRecord, mas é muito fácil no SQL.
Tudo o que você está tentando fazer é abrir o
deal_goal
arrays e construir um histograma baseado nos arrays abertos. Você pode expressar isso diretamente no SQL desta maneira:with expanded_deals(id, goal) as (
select id, unnest(deal_goal)
from deals
)
select goal, count(*) n
from expanded_deals
group by goal
E se você quiser incluir todas as quatro metas, mesmo que elas não apareçam em nenhum dos
deal_goal
s, em seguida, basta lançar um LEFT JOIN para dizer isso: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
Demonstração de SQL :http://sqlfiddle.com/#!15/3f0af/20
Jogue um desses em um
select_rows
ligue e você obterá seus dados:Deal.connection.select_rows(%q{ SQL goes here }).each do |row|
goal = row.first
n = row.last.to_i
#....
end
Provavelmente há muita coisa acontecendo aqui que você não conhece, então vou explicar um pouco.
Em primeiro lugar, estou usando WITH e Common Table Expressions (CTE) para simplificar os SELECTs. COM é um recurso SQL padrão que permite produzir macros SQL ou tabelas temporárias embutidas de uma espécie. Na maioria das vezes, você pode pegar o CTE e soltá-lo diretamente na consulta onde está o nome:
with some_cte(colname1, colname2, ...) as ( some_pile_of_complexity )
select * from some_cte
é como isso:
select * from ( some_pile_of_complexity ) as some_cte(colname1, colname2, ...)
CTEs são a maneira SQL de refatorar uma consulta/método excessivamente complexo em partes menores e mais fáceis de entender.
unnest
é uma função de matriz que descompacta uma matriz em linhas individuais. Então, se você disser unnest(ARRAY[1,2])
, você obtém duas linhas de volta:1
e 2
. VALORES no PostgreSQL é usado para, mais ou menos, gerar tabelas constantes embutidas. Você pode usar VALUES em qualquer lugar que possa usar uma tabela normal, não é apenas uma sintaxe que você lança em um INSERT para informar ao banco de dados quais valores inserir. Isso significa que você pode dizer coisas como:
select * from (values (1), (2)) as dt
e obtenha as linhas
1
e 2
Fora. Lançar esses VALUES em um CTE torna as coisas agradáveis e legíveis e faz com que pareça com qualquer tabela antiga na consulta final.