Как сделать сумму массива месяца из запроса Postgresql в Rails 3

Я новичок в программировании, но вот в чем дело: я пытаюсь создать приложение для рельсов, которое берет данные из базы данных postgresql и показывает сводку в диаграмме jqPlot, но у меня проблемы с моими запросами. Мне нужен массив для диаграммы, который будет отформатирован примерно так: total_durations=[["Jan", 3456],["Feb", 21] и т. д.]

Вот таблица usagedata в моей базе данных:

╔═══════════════╦═════════════╦═════════════════════╦════════════════╗
║   record_id   ║   user_id   ║     submit_time     ║   duration     ║
╠═══════════════╬═════════════╬═════════════════════╬════════════════╣
║             1 ║           6 ║ 2012-09-19 22:18:58 ║      45        ║
║             2 ║           1 ║ 2012-09-19 22:45:59 ║      0         ║
║             3 ║           5 ║ 2012-09-20 01:57:52 ║      3987      ║
║             4 ║           8 ║ 2012-09-18 03:47:53 ║      34        ║
║             5 ║           9 ║ 2013-01-26 20:38:03 ║      678       ║
║             6 ║           1 ║ 2013-01-26 23:41:44 ║      56        ║
║             7 ║           2 ║ 2013-01-27 02:10:41 ║      100       ║
╚═══════════════╩═════════════╩═════════════════════╩════════════════╝

<сильный>1. Частичный метод
У меня есть Model Usagedata.rb:

class Usagedata < ActiveRecord::Base     
  def self.by_month     
   h = Usagedata.calculate(:sum, :duration, :conditions => {     
     :submit_time => (Time.now.all_year) },    
     :order => "EXTRACT(month FROM submit_time)",     
     :group => ["EXTRACT(month FROM submit_time)","EXTRACT(year FROM submit_time)"])  

  end 
end    

использование контроллераdata_controller.rb:

class UsagedataController < ApplicationController     
    def index    
    end
    private
    def set_usagedata
      @usagedata = Usagedata.find(params[:id])
    end
    def usagedata_params
      params[:usagedata]
    end
end

И просмотрите index.html.haml:

%br=h = Usagedata.by_month

Вывод представления:

{[1.0, 2013.0]=>135776897, [2.0, 2013.0]=>100620585, [3.0, 2013.0]=>162980319, [4.0, 2013.0]=>26916589, [5.0, 2013.0]=>18793323, [6.0, 2013.0]=>9250440, [7.0, 2013.0]=>5011563, [12.0, 2012.0]=>24092}

Как я могу получить массив total_durations=[["Jan", 3456],["Feb", 21], etc] в соответствии с таблицей базы данных, где месяц берется из поля submit_time, а другое число представляет собой сумму длительностей, сделанных каждый месяц. Или даже массив типа total_durations=[["1.0, 2013.0", 135776897],["2.0, 2013.0", 100620585], etc] поможет.

<сильный>2. Частичный метод
Мне удалось получить то, что мне нужно, в БД:

select to_char(submit_time,'Mon') as mon,
   extract(year from submit_time) as yyyy,
   sum("duration") as "Total_Duration"
from usagedata
group by 1,2

но как я могу получить вывод запроса в массив в Rails?

Я пробовал это на своей странице html.haml:

%br=Usagedata.select("duration, extract (month from submit_time) as month, extract(year from submit_time) as year, SUM(submit_time) as total").group(1,2)

Но это просто строка печати:

#<ActiveRecord::Relation::ActiveRecord_Relation_Usagedata:0x007f1c10997518>

Также попытался добавить его в свой контроллер как:

@fetch = []
  Usagedata.select("extract (month from submit_time) as month, extract(year from submit_time) as year, SUM(duration)").group_by(1,2).each do |ph|
    @fetch << [ph.month.to_f, ph.year, ph.sum]
end

Но это просто дает мне ошибку:

PG::Error: ERROR: column "usagedata.submit_time" must appear in the GROUP BY clause or be used in an aggregate function LINE 1: SELECT extract (month from submit_time) as month, extract(ye... ^ : SELECT extract (month from submit_time) as month, extract(year from submit_time) as year, SUM(duration) FROM "usagedata"

<сильный>3. Частичный метод
Описан здесь: http://railsforum.com/viewtopic.php?id=27205
controller.rb:

    @usagedata_groups = Usagedata.find(:all,
    :select => 'submit_time, wall_duration, id', 
    :conditions => {:machine_name_id => ["1"]},).group_by{|usagedata| usagedata.submit_time.beginning_of_month}

    @fetch = []
    Usagedata.find(:all,
    :select => 'submit_time, wall_duration, id', 
    :conditions => {:machine_name_id => ["1"]},).group_by{|usagedata| usagedata.submit_time.beginning_of_month}.keys.sort.each do |month|
       @fetch << month.strftime("%B %Y")
       @fetch << month.collect(&:wall_duration).sum
    end

index.html.haml

  %table
    %tr         
     %th    
     - @usagedata_groups.keys.sort.each do |month|        
       %tr
        %td
          #{month.strftime("%B %Y")}          
        %td
          #month.collect(&:wall_duration).sum 
  %table
    %tr
     %th Show @fetch content:    
     - @fetch.each do |co|
       %tr 
        %td=co

Вывод без строки @fetch << month.collect(&:wall_duration).sum в контроллере:

February 2013     98503443
March 2013            162980319
April 2013            26916589
May 2013              18793323
June 2013             9250440
July 2013             5399525

Show @fetch content
February 2013
March 2013
April 2013
May 2013
June 2013
July 2013

с этой строкой я получаю сообщение об ошибке:

NoMethodError in UsagedataController#index
undefined method `collect' for Fri, 01 Feb 2013 00:00:00 UTC +00:00:Time

Пожалуйста помоги!


person user2586273    schedule 16.07.2013    source источник
comment
Не похоже, что вы получите лучшую производительность, запрос в порядке. Однако, если вы хотите использовать Rails ActiveRecord для удобства, продолжайте. У вас есть вся необходимая информация здесь: guides.rubyonrails.org/active_record_querying.html   -  person bluehallu    schedule 16.07.2013
comment
Вы можете получить лучшую производительность, если вместо этого будете анализировать даты и суммировать продолжительность в ruby.   -  person Damien Roche    schedule 16.07.2013
comment
@Hallucynogenyc Я отредактировал свой пост для получения дальнейших инструкций. Кажется, я не могу найти способ сделать запрос в правильный массив сейчас. :/   -  person user2586273    schedule 16.07.2013
comment
Сейчас не могу посмотреть, потом посмотрю. Однако НИКОГДА не обращайтесь к БД из представления, для чего предназначен контроллер. Сделайте этот запрос в контроллере, сохраните результат в переменной экземпляра, а затем получите доступ к нему из представления.   -  person bluehallu    schedule 16.07.2013
comment
@DamienRoche: я сомневаюсь, что синтаксический анализ и суммирование дат в памяти будут более производительными, чем если бы это делала база данных.   -  person Dan McClain    schedule 29.10.2013
comment
Для вашей первой части: {[1.0, 2013.0]=>135776897, [2.0, 2013.0]=>100620585, [3.0, 2013.0]=>162980319, [4.0, 2013.0]=>26916589, [5.0, 2013.0]=>18793323, [6.0, 2013.0]=>9250440, [7.0, 2013.0]=>5011563, [12.0, 2012.0]=>24092} Вы можете сделать: {[1.0, 2013.0]=>135776897, [2.0, 2013.0]=>100620585, [3.0, 2013.0]=>162980319, [4.0, 2013.0]=>26916589, [5.0, 2013.0]=>18793323, [6.0, 2013.0]=>9250440, [7.0, 2013.0]=>5011563, [12.0, 2012.0]=>24092}.map{ |k,v| [k.join(', '), v] } что должно дать желаемый результат.   -  person Surya    schedule 27.12.2013
comment
И, как упоминал @Hallucynogenyc, пожалуйста, не делайте запросы к базе данных в представлениях, даже не пишите их в контроллерах. Напишите такие запросы к базе данных в моделях, а затем используйте метод модели для извлечения данных, назначьте их переменной, а затем используйте эту переменную в представлении. :)   -  person Surya    schedule 27.12.2013