I faced this problem to have a sqlite database from an existing mysql.. and being the rails guy... i made it the rails way.. but of course there are other option available which will be fast .. this is kind of slow... but works for small stores :))
Steps are..
1. Create a source model which is connected with mysql connection/using mysql adaptor
class SourceDB < ActiveRecord::BaseendSourceDB.establish_connection($config["database_mysql"])
2. Create a destination model which is connected with sqlite connection/using sqlite adaptor
class TargetDB < ActiveRecord::BaseendTargetDB.establish_connection($config["database_sqlite"])
3. Create schema from source database so that can reproduce it in destination(sqlite) database.
File.open(name_of_schema_file,"w") do |file|ActiveRecord::SchemaDumper.dump(SourceDB.connection, file)end
4. Alter the generated schema file to remove line which contains "add_index" as these are of no use in sqlite conversion process
5. Then load the altered schema file (change the ActiveRecord::Base.connection to point to destination database before loading)
ActiveRecord::Base.connection = TargetDB.connectionload(name_of_schema_file)
6. and now resurvely iterate with all tables in source database and transport it to derstination (sqlite) database
Source file [mysql_to_sqlite.rb]
require 'rubygems'require 'active_record'require 'active_support'require 'sqlite3'require 'active_record/schema_dumper'require "yaml"require "create_class.rb"t1 = Time.now$config = YAML.load_file("config/config.yml")name_of_schema_file = ($config["schema_file"])class SourceDB < ActiveRecord::BaseendSourceDB.establish_connection($config["database_mysql"])class TargetDB < ActiveRecord::BaseendTargetDB.establish_connection($config["database_sqlite"])puts "dumping the schema"File.open(name_of_schema_file,"w") do |file|ActiveRecord::SchemaDumper.dump(SourceDB.connection, file)endputs "discarding index(es)"line_array = Array.newFile.open(name_of_schema_file,"r") do |file|file.each { |line| line_array << line unless line.include?("add_index")}endFile.rename(name_of_schema_file, "original_#{name_of_schema_file}")File.open(name_of_schema_file,"w") do |file|file.puts(line_array)endputs "loading the schema"ActiveRecord::Base.connection = TargetDB.connectionload(name_of_schema_file)SourceDB.connection.tables.each do |tbl|puts "Table_initiated: #{tbl.inspect}"SourceDB.set_table_name tblSourceDB.set_inheritance_column ""create_class('TargetModel', TargetDB) doset_table_name tblset_inheritance_column ""endputs "=========for table: #{tbl}=========="total_record_in_table = SourceDB.count_by_sql("SELECT COUNT(*) from #{tbl}")tub_size = 1000no_of_iteration = ((total_record_in_table % tub_size) == 0) ? (total_record_in_table / tub_size) : ((total_record_in_table / tub_size) + 1)for j in 0..(no_of_iteration-1)current_record_set = SourceDB.find(:all,:offset => (j*tub_size), :limit => (tub_size - 1))current_record_set.each_with_index do |record,ind|record_copy = TargetModel.newrecord.attributes.each do |key,value|record_copy.send("#{key}=",value)endrecord_copy.saveputs "Completed: #{((j*tub_size) + ind)} of #{total_record_in_table} with id: #{record_copy.id} ."endendendt2 = Time.nowputs "Process initiated at: #{t1}"puts "Process completed at: #{t2}"puts "Time elapsed : #{t2-t1} seconds"
Source file [create_class.rb]
def create_class(class_name, superclass, &block)klass = Class.new superclass, &blockObject.const_set class_name, klassend
Configuration file [config.yml]
database_mysql:adapter: mysqldatabase: databse_nameusername: rootpassword: xxxxxxxxhost: xxx.xx.x.xxxtimeout: 5000encoding: utf8database_sqlite:adapter: sqlite3database: sqlite_database_file_with_path.dbschema_file: schema.txt
Great work mate! I've almost gotten this solution to work
ReplyDeleteBut sadly it fails at the followin line:
ActiveRecord::Base.connection = TargetDB.connection
After some research I still don't see what it's supposed to achieve nor if it should be there at all.
Hi telamon,
ReplyDeleteSorry was on a small holiday trip.
I can surely help you on this if you can provide me more info on what is the error you were/are getting
Praveen,
ReplyDeleteGreat work on this! I'm trying to implement it but am getting an error from this line:
ActiveRecord::Base.connection = TargetDB.connection
The error is:
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1959:in "method_missing": undefined method "connection=" for ActiveRecord::Base:Class (NoMethodError)
Any ideas?
Thanks!
-Matt