Czy istnieje powód (inny niż wspomniana już data), dla którego nie chciałbyś korzystać z wbudowanych funkcji grupowania w ActiveRecord? Wydajesz się być zaniepokojony „przetwarzaniem końcowym”, o które nie sądzę.
Jesteś w Railsach, więc prawdopodobnie powinieneś najpierw poszukać rozwiązania Railsowego[1]. Moją pierwszą myślą byłoby zrobienie czegoś takiego jak
Product.average(:sales_price, :group => "DATE(created_at)", :conditions => ["merchant_id=?", 1])
który ActiveRecord zamienił się w prawie opisany przez Ciebie SQL. Zakładając, że zadeklarowano has_many
powiązanie między Sprzedawcą a Produktem, wtedy prawdopodobnie lepiej byłoby to wykorzystać, więc coś takiego:
ave_prices = Merchant.find(1).products.average(:sales_price, :group => "DATE(created_at)")
(Mam nadzieję, że Twój opis modelu jako „products_sold” jest jakimś rodzajem błędu w transkrypcji, przy okazji – jeśli nie, to trochę nie rozumiesz nazwy swojej klasy!)
Po tym wszystkim jesteś z powrotem tam, gdzie zacząłeś, ale dotarłeś tam w bardziej konwencjonalny sposób Rails (a Rails naprawdę ceni konwencje!). Teraz musimy wypełnić luki.
Zakładam, że znasz swój zakres dat, powiedzmy, że jest zdefiniowany jako wszystkie daty od from_date
do to_date
.
date_aves = (from_date..to_date).map{|dt| [dt, 0]}
To buduje pełną listę dat w postaci tablicy. Nie potrzebujemy dat, w których uzyskaliśmy średnią:
ave_price_dates = ave_prices.collect{|ave_price| ave_price[0]} # build an array of dates
date_aves.delete_if { |dt| ave_price.dates.index(dt[0]) } # remove zero entries for dates retrieved from DB
date_aves.concat(ave_prices) # add the query results
date_aves.sort_by{|ave| ave[0] } # sort by date
Dla mnie ta część wygląda na trochę zagraconą:myślę, że mogłaby być zwięźlejsza i czystsza. Badałbym budowanie skrótu lub struktury zamiast pozostawania w tablicach.
[1] Nie mówię, że nie używaj SQL - zdarzają się sytuacje, w których ActiveRecord nie może wygenerować najbardziej wydajnego zapytania i wracasz do find_by_sql
. W porządku, tak powinno być, ale myślę, że powinieneś spróbować użyć tego tylko w ostateczności.