A reader in the Ruby forum recently asked about using Ruby to get data from a Microsoft Access database. This can be done easily using the ActiveX Data Objects (ADO), via the win32ole library. Let's walk through it...
As usual, require the win32ole library:
require 'win32ole'
Next, create a new ADODB Connection object, which will manage the connection to the database:
connection = WIN32OLE.new('ADODB.Connection')
To open a connection to the Access database, call the Connection object's Open method, passing it the Provider and Data Source (your Access mdb file) parameters:
connection.Open('Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\baseball\lahman54.mdb')
To execute an SQL statement that does not return a recordset (ie, CREATE, ALTER, INSERT), you can call the Connection object's Execute method:
connection.Execute("INSERT INTO HallOfFame VALUES ('Dave', 'Concepcion');")
To perform a query that returns a recordset of data, first create a new ADODB Recordset object:
recordset = WIN32OLE.new('ADODB.Recordset')
Then call the Recordset object's Open method, passing it the SQL statement and your existing Connection object:
recordset.Open(sql, connection)
This loads the query results into the Recordset object. The Recordset object's GetRows method returns an array of columns (not rows, as you might expect), so we'll use the Ruby array's transpose method to convert it to an array of rows:
data = recordset.GetRows.transpose
Close the Connection object by calling its Close method:
recordset.Close
We could create a simple class to wrap up this functionality:
class AccessDb
attr_accessor :mdb, :connection, :data, :fields
def initialize(mdb=nil)
@mdb = mdb
@connection = nil
@data = nil
@fields = nil
end
def open
connection_string = 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source='
connection_string << @mdb
@connection = WIN32OLE.new('ADODB.Connection')
@connection.Open(connection_string)
end
def query(sql)
recordset = WIN32OLE.new('ADODB.Recordset')
recordset.Open(sql, @connection)
@fields = []
recordset.Fields.each do |field|
@fields << field.Name
end
begin
@data = recordset.GetRows.transpose
rescue
@data = []
end
recordset.Close
end
def execute(sql)
@connection.Execute(sql)
end
def close
@connection.Close
end
end
This class is very similar to an SqlServer class I previously discussed.
We would use this AccessDb class as follows:
db = AccessDb.new('c:\Baseball\lahman54.mdb')
db.open
db.query("SELECT * FROM AllStar WHERE playerID = 'conceda01';")
field_names = db.fields
rows = db.data
db.execute("INSERT INTO HallOfFame VALUES ('Dave', 'Concepcion');")
db.close
That about wraps up our show for today. As always, feel free to post a comment here or email me with questions, comments, or suggestions.
Thanks for stopping by!
15 comments:
Awesome, this blog gets better and better. This kind of information is really sorely lacking out there in the Rubysphere and you're filling that gap nicely. Kudos.
Thank you very much, Charles!
David
I guess Charles says it all very well. Not all, but he tries. :o)
I really think we are missing the message in this post. The power of Win32 OLE has been leveraged here. It's not just accessing DBs. It is using OLE.
So, what about an ActiveRecord provider for Access?
It's possible to use ADODB.Connection to work wiht excel files like this python example:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440661
@Daniel:
I haven't seen a Jet (MS Access) database adapter yet. I know that an SqlServer adapter exists, though. If it utilizes ADO, it may be possible to modify its connection string to work with Jet databases. Perhaps I'll look into it, if no one else has done so; but I don't know how soon that could be.
Dont forget that you need set sql value. In fact that value is the one that is in connection.execute. On the top of the page. connection.Execute("INSERT INTO HallOfFame VALUES ('Dave', 'Concepcion');")
You can change it by:
sql = "INSERT INTO HallOfFame VALUES ('Dave', 'Concepcion');"
I hope this will be usefull. Bye
Thanks for the hint in using the powerfull 'win32ole'.
For my needs I tried to use AdoX with Ruby to replace spaces in Access field names, and it worked fine. Here is the code:
# SpaceRep.rb
require 'win32ole'
connection = WIN32OLE.new('ADODB.Connection')
'Data Source = is your Access file
connection.Open('Provider=Microsoft.Jet.OLEDB.4.0;Data Source=users.mdb')
cat = WIN32OLE.new("ADOX.Catalog")
cat.ActiveConnection = connection
print "Inform your table name: "
yourtable = gets.chomp
print yourtable, "\n"
# loop through each field in the table replacing the Spaces by what you want - in my case "_"
for col in 0..cat.Tables(yourtable).Columns.Count - 1
cat.Tables(yourtable).Columns(col).Name = cat.Tables(yourtable).Columns(col).Name.gsub(" ", "_")
end
print "Task completed! Check your database."
gets
Sorry, please correct the above line to be a ruby comment starting with #, as following:
# Data Source = is your Access file
Thanks. This post just saved me several hours. I'm a big fan of code which integrates between open source and 'closed' systems, and this particular wedge allows me to crack a closed system's data wide open.
You're welcome, Patrick!
"This post just saved me several hours."
Another Ruby on Windows success story!
[grin]
David
A Microsoft Access adapter for Rails has been made (Rails MS Access Adapter).
It probably won't work with the latest ActiveRecord, as it's not an adapter gem; though with older versions it works great.
Very nice posting. I got a software stellar phoenix access repair which repair and recover corrupted mdb database and MS access files. It is a powerful and robust software and easy to use.
Thanks
Wow thanks for this post! It is really helpful.. best regards, nikolai
It just works. Thank you!
Post a Comment