2012-03-08 32 views
5

Tôi đang tạo tập lệnh Ruby để nhập tệp văn bản được phân tách bằng tab có khoảng 150k dòng vào SQLite. Dưới đây là cho đến nay:Chuỗi thoát cho Ruby SQLite Chèn

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 

Các lỗi script ra trên dòng đầu tiên chứa một giá duy nhất bất chấp sự gsub để thoát khỏi dấu nháy đơn trong phương pháp prepare_for_insert tôi:

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

Nó erroring ra trên dòng 15. Nếu tôi kiểm tra dòng đó với puts string[14], tôi có thể thấy nơi nó hiển thị lỗi gần "s". Có vẻ như sau: 'Touch the Top of the World: A Blind Man\'s Journey to Climb Farther Than the Eye Can See'

Dường như một báo giá bị thoát, vậy tại sao tôi vẫn gặp lỗi?

Trả lời

10

Không làm điều đó như vậy chút nào, nội suy chuỗi và SQL có xu hướng là kết hợp kém. Sử dụng một tuyên bố chuẩn bị thay vào đó và để cho các hợp đồng lái xe với trích dẫn và thoát:

# 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) } 

Bạn nên thay thế column_name với tên cột thực sự của khóa học; bạn không cần phải chỉ định các tên cột trong một INSERT nhưng bạn nên luôn làm điều đó. Nếu bạn cần chèn thêm cột thì hãy thêm các phần giữ chỗ và đối số vào ins.execute.

Sử dụng prepareexecute nên nhanh hơn, an toàn hơn, dễ dàng hơn, và nó sẽ không làm cho bạn cảm thấy như bạn đang viết PHP vào năm 1999.

Ngoài ra, bạn nên sử dụng standard CSV parser phân tích của bạn tách biệt bởi tab các tập tin, định dạng XSV không có nhiều thú vị để đối phó với (chúng hoàn toàn xấu xa trong thực tế) và bạn có những điều tốt hơn để làm với thời gian của bạn hơn là đối phó với các trường hợp vô nghĩa và cạnh của họ và những gì không.

+0

Hoàn hảo. Nó hoạt dộng bây giờ. Có 34 cột. Vì vậy, ngốc nghếch như nó trông, '(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,? ,?,?,?,?,?,?,?,?,?,?,?,?,?,?) 'là cách chính xác để thể hiện số cột dự kiến? Tôi cũng sẽ kết hợp trình phân tích cú pháp CSV. – michaelmichael

+3

@michaelmichael: Có, và 34 đối số cho 'ins.execute' nhưng bạn có thể đặt/giữ các đối số trong một mảng và' ins.execute (* array) 'chúng để giữ cho goofiness trong kiểm tra. Bạn cũng có thể xây dựng trình giữ chỗ bằng cách sử dụng '(['?'] * 34) .join (',')' (điều này không sao khi bạn biết chính xác chuỗi nào bạn đang làm việc, cố gắng sử dụng các chuỗi không xác định trong SQL yêu cầu sự cố). –