Jeg kan ikke komme i tanke om nogen ren måde at få de resultater, du leder efter gennem ActiveRecord, men det er ret nemt i SQL.
Det eneste, du virkelig prøver at gøre, er at åbne deal_goal
arrays og opbygg et histogram baseret på de åbnede arrays. Du kan udtrykke det direkte i SQL på denne måde:
with expanded_deals(id, goal) as (
select id, unnest(deal_goal)
from deals
)
select goal, count(*) n
from expanded_deals
group by goal
Og hvis du vil inkludere alle fire mål, selvom de ikke vises i nogen af deal_goal
s så bare smid et LEFT JOIN ind for at sige det:
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
Smid en af dem i en select_rows
ring og du får dine data:
Deal.connection.select_rows(%q{ SQL goes here }).each do |row|
goal = row.first
n = row.last.to_i
#....
end
Der sker sikkert meget her, som du ikke er bekendt med, så jeg vil forklare lidt.
Først og fremmest bruger jeg WITH og Common Table Expressions (CTE) til at forenkle SELECT'erne. WITH er en standard SQL-funktion der giver dig mulighed for at producere SQL-makroer eller indlejrede midlertidige tabeller af en slags. For det meste kan du tage CTE'en og slippe den lige i forespørgslen, hvor dens navn er:
with some_cte(colname1, colname2, ...) as ( some_pile_of_complexity )
select * from some_cte
er sådan her:
select * from ( some_pile_of_complexity ) as some_cte(colname1, colname2, ...)
CTE'er er SQL-metoden til at omstrukturere en alt for kompleks forespørgsel/metode til mindre og lettere at forstå stykker.
unnest
er en array-funktion, som udpakker et array i individuelle rækker. Så hvis du siger unnest(ARRAY[1,2])
, får du to rækker tilbage:1
og 2
.
VÆRDIER i PostgreSQL bruges til mere eller mindre at generere indlejrede konstanttabeller. Du kan bruge VALUES overalt, hvor du kan bruge en normal tabel, det er ikke kun en eller anden syntaks, du smider en INSERT ind for at fortælle databasen, hvilke værdier, der skal indsættes. Det betyder, at du kan sige ting som dette:
select * from (values (1), (2)) as dt
og få rækkerne 1
og 2
ud. At smide disse VALUES ind i en CTE gør tingene pæne og læsbare og får det til at ligne enhver gammel tabel i den endelige forespørgsel.