我正在创建一个 Ruby 脚本,将一个大约 150k 行的制表符分隔文本文件导入到 SQLite 中。到目前为止是这样的:
require 'sqlite3'
file = File.new("/Users/michael/catalog.txt")
string = []
# Escape single quotes, remove newline, split on tabs,
# wrap each item in quotes, and join with commas
def prepare_for_insert(s)
s.gsub(/'/,"\\\\'").chomp.split(/\t/).map {|str| "'#{str}'"}.join(", ")
end
file.each_line do |line|
string << prepare_for_insert(line)
end
database = SQLite3::Database.new("/Users/michael/catalog.db")
# Insert each string into the database
string.each do |str|
database.execute( "INSERT INTO CATALOG VALUES (#{str})")
end
脚本在包含单引号的第一行出错,尽管gsub
转义我的单引号prepare_for_insert
method:
/Users/michael/.rvm/gems/ruby-1.9.3-p0/gems/sqlite3-1.3.5/lib/sqlite3/database.rb:91:
in `initialize': near "s": syntax error (SQLite3::SQLException)
第 15 行出错。如果我用以下命令检查该行puts string[14]
,我可以看到“s”附近哪里显示错误。它看起来像这样:'Touch the Top of the World: A Blind Man\'s Journey to Climb Farther Than the Eye Can See'
看起来单引号已被转义,那么为什么我仍然收到错误?
根本不要这样做,字符串插值和 SQL 往往是一个糟糕的组合。请改用准备好的语句,让驱动程序处理引用和转义:
# Ditch the gsub in prepare_for_insert and...
db = SQLite3::Database.new('/Users/michael/catalog.db')
ins = db.prepare('insert into catalog (column_name) values (?)')
string.each { |s| ins.execute(s) }
你应该更换column_name
当然是真实的列名;您不必在 INSERT 中指定列名,但无论如何您都应该这样做。如果您需要插入更多列,请添加更多占位符和参数ins.execute
.
Using prepare http://rubydoc.info/github/luislavena/sqlite3-ruby/master/SQLite3/Database#prepare-instance_method and execute http://rubydoc.info/github/luislavena/sqlite3-ruby/master/SQLite3/Statement#execute-instance_method应该更快、更安全、更简单,而且它不会让您觉得自己是在 1999 年编写 PHP。
另外,您应该使用标准 CSV 解析器 http://ruby-doc.org/stdlib-1.9.3/libdoc/csv/rdoc/CSV.html要解析制表符分隔的文件,XSV 格式处理起来并不有趣(事实上它们是彻头彻尾的邪恶),而且你有更好的事情可以做,而不是处理它们的废话和边缘情况等等。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)