Skip to content

Instantly share code, notes, and snippets.

@NoTimeForHero
Created March 3, 2023 09:26
Show Gist options
  • Save NoTimeForHero/ca1711a158e559743c08b5abafaa31d9 to your computer and use it in GitHub Desktop.
Save NoTimeForHero/ca1711a158e559743c08b5abafaa31d9 to your computer and use it in GitHub Desktop.
Реализация Bulk Insert для PostgreSQL в Rails 5
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
def self.bulk_insert(data)
# @type [PG::Connection] conn
conn = self.connection.raw_connection
raise NotImplementedError.new 'Database Driver not supported!' unless conn.class.to_s == 'PG::Connection'
raise ArgumentError "Data not an Array of Hashes!" unless data.is_a?(Array) && data.all? {|rec| rec.is_a? Hash }
return nil unless data.count > 0
fields = data[0].keys
values = data.map { |item| item.values }
# Создаём Prepared Statement
prepared_name = 'bulk_insert'
begin
conn.exec("DEALLOCATE #{prepared_name}")
rescue PG::InvalidSqlStatementName
# Ignored
end
raw_fields = fields.map { |key| conn.escape_string(key)}.join(', ')
raw_values = fields.each_with_index.map { |x,index| "$#{index+1}" }.join(', ')
conn.prepare(prepared_name, "INSERT INTO #{self.table_name} (#{raw_fields}) VALUES(#{raw_values})")
# Запускаем в транзации insert для каждой записи
conn.exec("START TRANSACTION")
values.each { |record| conn.exec_prepared(prepared_name, record) }
conn.exec("COMMIT")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment