Jag kan inte komma på något rent sätt att få de resultat du är ute efter genom ActiveRecord, men det är ganska enkelt i SQL.
Allt du verkligen försöker göra är att öppna deal_goal
matriser och bygga ett histogram baserat på de öppnade matriserna. Du kan uttrycka det direkt i SQL på detta sätt:
with expanded_deals(id, goal) as (
select id, unnest(deal_goal)
from deals
)
select goal, count(*) n
from expanded_deals
group by goal
Och om du vill inkludera alla fyra målen även om de inte visas i något av deal_goal
s släng sedan bara in en LEFT JOIN för att säga så:
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-demo :http://sqlfiddle.com/#!15/3f0af/20
Kasta en av dessa i en select_rows
ring så får du din data:
Deal.connection.select_rows(%q{ SQL goes here }).each do |row|
goal = row.first
n = row.last.to_i
#....
end
Det händer förmodligen mycket här som du inte är bekant med så jag ska förklara lite.
Först och främst använder jag WITH och Common Table Expressions (CTE) för att förenkla SELECT. WITH är en standard SQL-funktion som gör att du kan skapa SQL-makron eller infogade temporära tabeller av något slag. För det mesta kan du ta CTE och släppa den direkt i frågan där dess namn är:
with some_cte(colname1, colname2, ...) as ( some_pile_of_complexity )
select * from some_cte
är så här:
select * from ( some_pile_of_complexity ) as some_cte(colname1, colname2, ...)
CTE:er är SQL-sättet att omstrukturera en alltför komplex fråga/metod till mindre och lättare att förstå delar.
unnest
är en arrayfunktion som packar upp en array i individuella rader. Så om du säger unnest(ARRAY[1,2])
, får du två rader tillbaka:1
och 2
.
VÄRDEN i PostgreSQL används för att mer eller mindre generera infogade konstanttabeller. Du kan använda VALUES var som helst du kan använda en normal tabell, det är inte bara någon syntax som du lägger in en INSERT för att tala om för databasen vilka värden som ska infogas. Det betyder att du kan säga så här:
select * from (values (1), (2)) as dt
och hämta raderna 1
och 2
ut. Att slänga in dessa VÄRDEN i en CTE gör saker trevliga och läsbara och får det att se ut som vilken gammal tabell som helst i den slutliga frågan.