2012-03-08 10 views
5

Rubyスクリプトを作成して、約150k行のタブ区切りのテキストファイルをSQLiteにインポートします。ここでは、これまでのところです:gsubにもかかわらず、単一引用符を含む最初の行にRuby 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 

スクリプトエラーうちは私のprepare_for_insert方法で単一引用符をエスケープする:それはアウトにerroringだ

/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) 

puts string[14]でその行を調べると、「s」の近くにエラーが表示されている箇所がわかります。これは次のようになります:'Touch the Top of the World: A Blind Man\'s Journey to Climb Farther Than the Eye Can See'

一重引用符がエスケープされているように見えますが、どうして私はまだエラーが表示されますか?

答えて

10

文字列補間と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に追加します。

prepareexecuteを使用すると、より高速である必要があり、より安全、より簡単に、そしてそれはあなたがまた1999年

にPHPを書いているように、あなたはタブ区切りを解析するstandard CSV parserを使用する必要があります感じていただけないでしょうXSV形式は扱うのが面倒ではありません(彼らは実際にはまったく悪です)。そして、あなたは、ナンセンスやエッジの場合に対処するよりも、あなたのより良いことがあります。

+0

パーフェクト。それは今働く。 34列あります。だから、見た目がグーフィーです。「(?、?、?、?、?、?、?、?、?、?、?、?、?、?、?期待される列数を表現する正しい方法ですか?私はCSVパーサーも組み込んでいます。 – michaelmichael

+3

@michaelmichael:はい、34個の引数を 'ins.execute'に入れますが、引数を配列に入れておき、' ins.execute(* array) 'することでgoofinessをチェックすることができます。また、 '(['?'] * 34).join( '、')'を使ってプレースホルダを構築することもできます(これは、あなたが使っている文字列を正確に知っていて、しかし、問題を尋ねる)。 –

関連する問題