以CSV格式导出SQLite3表的内容

时间:2013-05-16 16:20:11

标签: ruby csv sqlite

我有一个生成SQLite3数据库的Ruby脚本。

我希望能够生成一个包含其中一个数据库表的“output.csv”文件。

有没有办法在Ruby中处理它?<​​/ p>

3 个答案:

答案 0 :(得分:3)

使用Sequelto_csv

很容易
require 'sequel'
DB = Sequel.sqlite
# since Sequel 3.48.0 to_csv is deprecated, 
# we must load the to_csv feature via a extension
DB.extension(:sequel_3_dataset_methods) #define to_csv 
DB.create_table(:test){
  Fixnum :one
  Fixnum :two
  Fixnum :three
}
#Prepare some test data
5.times{|i|
  DB[:test].insert(i,i*2,i*3)
}

File.open('test.csv', 'w'){|f|
  f << DB[:test].to_csv
}

结果是:

one, two, three
0, 0, 0
1, 2, 3
2, 4, 6
3, 6, 9
4, 8, 12

在我的测试中,我遇到了行结尾的问题,因此我需要额外的gsub

File.open('test.csv', 'w'){|f|
  f << DB[:test].to_csv.gsub("\r\n","\n")
}

如果您想要不带标题行的导出,请使用to_csv(false)

备注:

    自liquel 3.48.0(2013-06-01)以来,
  • .to_csv已被弃用。 您可以将旧版本与gem 'sequel', '< 3.48.0'一起使用,也可以加载扩展名sequel_3_dataset_methods)。

要获得对其他分隔符和其他CSV功能的支持,您可以使用续集和CSV的组合:

require 'sequel'
require 'csv'
#Build test data
DB = Sequel.sqlite
DB.create_table(:test){
  Fixnum :one
  Fixnum :two
  Fixnum :three
  String  :four
}
#Prepare some test data
5.times{|i|
  DB[:test].insert(i,i*2,i*3, '<a href="www.test.com">test, no %i</a>' % i)
}

#Build csv-file
File.open('test.csv', 'w'){|f|
  DB[:test].each{|data| 
    f << data.values.to_csv(:col_sep=>';')
  }
}

结果:

0;0;0;"<a href=""www.test.com"">test, no 0</a>"
1;2;3;"<a href=""www.test.com"">test, no 1</a>"
2;4;6;"<a href=""www.test.com"">test, no 2</a>"
3;6;9;"<a href=""www.test.com"">test, no 3</a>"
4;8;12;"<a href=""www.test.com"">test, no 4</a>"

作为替代方案,您可以修补Sequel :: Dataset(修改后的代码来自marcalc at Github):

class Sequel::Dataset
    require 'csv'
    #
    #Options: 
    #* include_column_titles: true/false. default true
    #* Other options are forwarded to CSV.generate
    def to_csv(options={})
      include_column_titles = options.delete(:include_column_titles){true}  #default: true
      n = naked
      cols = n.columns
      csv_string = CSV.generate(options) do |csv|
        csv << cols if include_column_titles
        n.each{|r| csv << cols.collect{|c| r[c] } }
      end
      csv_string
    end 
end

答案 1 :(得分:1)

# Assume that model is an activerecord model
@secrets = Model.all
@csv = CSV.generate do |csv|
    @secrets.each { |secret|
            csv << ["#{secret.attr1.to_s}", "#{secret.attr2.to_s"] # and so on till your row is finished
    }
end
render :text => @csv, :content_type => 'application/csv'

如果您还有其他问题,请发表评论。

答案 2 :(得分:1)

添加了2020年的更新。自Sequel v5起,sequel_3_dataset_methods已被完全删除并且不可用。因此,将CSV作为数据库扩展名生成的操作也已完全删除。

看来,当前的“最佳实践”是将csv_serializer插件添加到Sequel::Model类中。不过这里有一个陷阱,就是您定义的Sequel::Model类必须在调用Sequel.connect之后定义。对Sequel :: Model进行子类化的操作会调用数据库中的读取。

这阻止了将类预定义为任何通用Gem的典型工作流程。

根据Sequel作者的说法,执行此操作的首选方法是通过内联MyClass = Class.new(Sequel::Model(:tablename))进行操作,否则只能在方法定义内调用require

不保证效率,这是一个定义“最佳实践”的代码示例。

require 'sequel'
require 'csv'

module SequelTsv
  class One
    def self.main
      db = Sequel.connect('sqlite://blog.db') # requires sqlite3

      db.create_table :items do
        primary_key :id
        String :name
        Float :price
      end

      items = db[:items] # Create a dataset

      items.insert(:name => 'abc', :price => rand * 100)
      items.insert(:name => 'def', :price => rand * 100)
      items.insert(:name => 'ghi', :price => rand * 100)

      item_class = Class.new(Sequel::Model(:items))

      item_class.class_eval do
        plugin :csv_serializer
      end

      tsv = item_class.to_csv(write_headers: true, col_sep:"\t")
      CSV.open('output.tsv', 'w') do |csv|
        CSV.parse(tsv) do | c |
          csv << c
        end
      end
    end
  end
end

SequelTsv::One.main

输出:

id  name    price
1   abc 39.307899453608364
2   def 99.28471503410731
3   ghi 58.0295131255661