2011-12-14 35 views
22

Tôi cần chèn một mảng email làm các bản ghi khác nhau vào bảng danh bạ của mình. Điều này có thể giải quyết như thế nào.Cách thực hiện chèn hàng loạt trong Rails 3

Eg: @email = ["[email protected]", "[email protected]", "[email protected]", ... ] 

Tôi không muốn sử dụng.

@email.each do |email| 
    @contact = Contact.new 
    @contact.email = email 
    @contact.save 
    end 

Nguyên nhân này sẽ chèn quires. Tôi chỉ cần một truy vấn chèn đơn để chèn các giá trị này. Làm thế nào điều này có thể được thực hiện trong đường ray 3.0.9 (và lý tưởng là MySQL). Xin vui lòng giúp

+0

Xem thêm: [Chèn số lượng lớn bản ghi vào bảng Bản ghi đang hoạt động] (http://stackoverflow.com/questions/15317837/bulk-insert-records-into-active-record-table) và [Chèn hàng loạt trong đường ray 3] (http://stackoverflow.com/questions/15784305/batch-insertion-in-rails-3). –

Trả lời

47

activerecord nhập thực hiện AR # nhập khẩu

activerecord-nhập khẩu là một thư viện dữ liệu số lượng lớn chèn sử dụng ActiveRecord.

xem làm thế nào nó hoạt động: nhà

books = [] 
10.times do |i| 
    books << Book.new(:name => "book #{i}") 
end 
Book.import books 

của dự án là trên Github và nó wiki.

+6

Đây là một Gem tuyệt vời, tôi rất vui vì bạn đã chỉ ra! –

+1

Tốc độ chèn hàng loạt đáng kể. –

+0

Ngoài ra, câu hỏi liên quan: http://stackoverflow.com/questions/13718013/how-do-i-retrieve-a-list-of-created-ids-for-bulk-insert-in-active-record, hãy xem câu trả lời thứ hai (không phải là câu trả lời được chấp nhận). Phiên bản SQL thô trả về tất cả các id. – Rob

4

Bạn cũng có thể thử upsert, xấp xỉ càng nhanh càng activerecord-import, nhưng chỉ hoạt động (hiện tại) với MySQL, Postgres, và SQLite3:

require 'upsert' 
Upsert.batch(Contact.connection, Contact.table_name) do |upsert| 
    emails.each do |email| 
    upsert.row(email: email) 
    end 
end 

Lưu ý rằng điều này liên quan đến một truy vấn cơ sở dữ liệu cho mỗi bản ghi, nhưng đó là một "lúng túng", vì vậy bạn không cần phải kiểm tra xem một bản ghi đã tồn tại chưa. Trong ví dụ của bạn, đây không phải là một mối quan tâm, nhưng trong hầu hết các ứng dụng nó sẽ trở thành một trong những cuối cùng.

+0

Có một truy vấn cơ sở dữ liệu trên mỗi bản ghi chính xác KHÔNG nhập số lượng lớn. Nhập số lượng lớn là có một câu lệnh SQL chèn với nhiều bộ tham số ràng buộc với nó, do đó bạn chỉ có một cơ sở dữ liệu vòng chuyến đi, và do đó nó nhanh. – Rob

+0

Thư viện 'upsert' bắt đầu bằng cách sử dụng' INSERT ON UPDATE DUPLICATE KEY UPDATE', phần lớn. –

+0

(oops, nhấn enter trước khi tôi hoàn toàn có thể giải thích bản thân mình) mặc dù nó không làm điều đó nữa, nó làm cho 1 chuyến đi đến db mỗi bản ghi, tôi nghĩ rằng thực tế lịch sử là lý do tại sao tôi unthinkingly không biện minh như thế nào 'upsert' theo ý kiến ​​của tôi, một dạng cập nhật hàng loạt. tôi sẽ xác định cập nhật hàng loạt là "thiết lập trạng thái mới trên nhiều bản ghi mà không quan tâm đến trạng thái hiện tại của chúng" - bao nhiêu lần đi db là một chi tiết quan trọng. "upserting" là một cách đặc biệt để thực hiện hàng loạt. xem https://github.com/seamusabshere/upsert/commit/b8365d91fe68e450382119 vì sao tôi ngừng sử dụng phương pháp 1 chuyến đi mỗi đợt. –

2

Cách đơn giản nhất mà không cần đá quý khác là để concat một và thực hiện nó trong một lần chèn SQL (http://www.electrictoolbox.com/mysql-insert-multiple-records/).

@email = ["[email protected]", "[email protected]", "[email protected]"] 

time = Time.current.to_s(:db) 

values = @email.map do |email| 
    "('#{email}', '#{time}', '#{time}')" 
end 

sql = "INSERT INTO contacts (email, created_at, updated_at) VALUES #{values.join(', ')}" 
Contact.connection.execute(sql) 
+0

Tôi đã thực hiện điều này, nhưng bây giờ tôi tự hỏi nếu nó có nguy cơ tiêm SQL nếu bạn đang sử dụng một cái gì đó nhiều hơn một chút hình thức miễn phí hơn một email. – Nuclearman

+0

@Nuclearman, tôi có cùng cảm giác về việc tiêm SQL –

Các vấn đề liên quan