Querying Multiple Tables With ActiveRecord
Saturday, April 10th, 2010The other day at work I was doing some data mining for our business intelligence folks. They needed to get some stats from the last year of billing transactions, and the task came to me. I had to hack up a perl script to query the archived data to find a certain type of transaction. Easy enough, the only minor issue was that since the data set was both huge and old, the table were broken up by month.
My perl script looked something like this (cleaned up for brevity):
@months = qw( 200901 200902 200903 ); # up to 201004 $sql = "select * from BillingMONTH where resultCode=40"; foreach my $month( @months ) { $sql_full = $sql; $sql_full =~ s/MONTH/$month/; # change the table name for each record $sth = $dbh->prepare($sql_full) or die; $sth->execute(); [ ... ] # retrieve the data, save/process it } |
I started wondering if these sorts of quick and dirty, but non-trivial scripts were easily doable in Ruby using Active Record.
I set up a similar situation on my system, a mysql database with 3 tables and a couple of rows of garbage data in them. I knew that I could get a database connection set up very fast by making a throwaway rails app, setting up the models in it, and then using script/console as my interface, but I’ve honestly never use activerecord in a scripting environment.
After some messing around I came up with this:
#!/usr/bin/ruby require 'rubygems' require 'active_record' ActiveRecord::Base.establish_connection( :adapter => "mysql", :username => "root", :password => "password", :database => "test" ) class Test < ActiveRecord::Base end %w( Archive201001 Archive201002 Archive201003 ).each do |tablename| res = Test.find( :all, :from => tablename, :conditions => "name like 'test%'" ); puts "Total results from #{tablename}: #{res.size.to_s}" # [...] other awesome processing on the res object end |
Running it gives me:
alan@phoenix:~/code/ruby$ ./testdb.rb Total results from Archive201001: 3 Total results from Archive201002: 6 Total results from Archive201003: 3 |
Whohoo! The one thing I couldn’t figure out is how to get rid of having to create a sub-class of the ActiveRecord::Base class. I technically can do it with:
ActiveRecord::Base.connection.execute("select * from #{tablename}") |
But I don’t know how to get this into the “object oriented” version to use the :conditions and
rder and such. However, the main point of can I replace perl and DBI for quick and dirty database scripting has most definitively been answered.
Next step: seeing how to do the same thing in Data Mapper (to keep @dkubb happy)