我有一个生成 SQLite3 数据库的 Ruby 脚本。
我希望能够生成一个包含其中一个数据库表的“output.csv”文件。
有没有办法在 Ruby 中处理这个问题?
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)
评论:
.to_csv
自 Sequel 3.48.0 (2013-06-01) 起已弃用。您可以使用旧版本gem 'sequel', '< 3.48.0'
或加载扩展sequel_3_dataset_methods
)。要获得对其他分隔符和其他 CSV 功能的支持,您可以结合使用 Sequel 和 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 (来自Github 的 marcalc帖子的修改代码):
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
# 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'
如果您还有其他问题,请发表评论。
添加 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