1566d4066e11205ec3e3aaeeaf89348b

Given an event with the following attributes:
name:string
start_date:datetime

I want to:
1) return events, grouped by the month/year of the start date.
2) ensure the events for each returned month/year are ordered by start_date

Is this possible using SQL ? Here's the ruby code I use to accomplish this.

I'm using rails 2.3.8, so I'd prefer answers that work for that. I'd be interested in seeing some rails 3 solutions too.

def self.group_by_month(events)
    event_hash = {}
    
    events.each do |event|
      start = event.start_date.to_s(:month_year)
      
      event_hash[start] ||= []
      event_hash[start] << event
    end

    event_hash.sort {|a,b| Time.parse(a[0]) <=> Time.parse(b[0]) }
  end

Refactorings

No refactoring yet !

B8ba61cc84ecb63c859435be28547dfb

steved

September 23, 2010, September 23, 2010 17:23, permalink

No rating. Login to rate!

Rails adds group_by to the Array returned by all.

# assume you have added :month_year to DateTime::DATE_FORMATS

events_by_month_year = events.group_by { |e| e.start_date.to_s(:month_year) }
1566d4066e11205ec3e3aaeeaf89348b

Luke

September 23, 2010, September 23, 2010 20:03, permalink

No rating. Login to rate!

Your code is much more succinct than mine, so it's certainly an improvement, but I'm still wondering if there's a solution that has the DB do most of the work.

D41d8cd98f00b204e9800998ecf8427e

steved

September 25, 2010, September 25, 2010 15:40, permalink

1 rating. Login to rate!
Event.all({
  :select => "*, concat(year(start_date), '-', month(start_date)) as month", 
  :group => "month", 
  :order => "month",
})
1566d4066e11205ec3e3aaeeaf89348b

Luke

September 27, 2010, September 27, 2010 05:15, permalink

No rating. Login to rate!

Very nice. This is exactly what I was looking for. For SQLITE the syntax is:
Event.all(:select => "*, strftime('%Y%m', start_date) as month", :order => "month", :group => "month")

Ideally it would return an array of arrays. Each of the sub-arrays being the contents of a given month. As it stands I get one event per month. So, I'll probably just remove the group clause and detect the month boundry as I iterate over the array.

Thanks again Steve!

Your refactoring





Format Copy from initial code

or Cancel