我如何使用" UPSERT"或者" INSERT INTO喜欢(user_id,person_id)VALUES(32,64)ON CONFLICT(user_id,person_id)DOHING"在PostgreSQL 9.5 on Rails 4.2?
答案 0 :(得分:0)
在这里查看active_record_upsert
gem:https://github.com/jesjos/active_record_upsert。这是upsert,但显然只在Postgres 9.5 +。
答案 1 :(得分:0)
您可以通过使用活动记录内部函数创建SQL来实现。您可以使用arel_attributes_with_values_for_create
为具有Rails属性的插入sql提取每个active_record的值,例如:
INSERT_REGEX = /(INSERT INTO .* VALUES) (.*)/
def values_for(active_record)
active_record.updated_at = Time.now if active_record.respond_to?(:updated_at)
active_record.created_at ||= Time.now if active_record.respond_to?(:created_at)
sql = active_record.class.arel_table.create_insert.tap do |insert_manager|
insert_manager.insert(
active_record.send(:arel_attributes_with_values_for_create, active_record.attribute_names.sort)
)
end.to_sql
INSERT_REGEX.match(sql).captures[1]
end
然后,您可以将所有值添加到一个大的“值”字符串中:
def values(active_records)
active_records.map { |active_record| values_for(active_record) }.join(",")
end
对于SQL的插入部分,您可以使用类似于用于值提取的代码:
INSERT_REGEX = /(INSERT INTO .* VALUES) (.*)/
def insert_statement(active_record)
sql = active_record.class.arel_table.create_insert.tap do |insert_manager|
insert_manager.insert(
active_record.send(:arel_attributes_with_values_for_create, active_record.attribute_names.sort)
)
end.to_sql
INSERT_REGEX.match(sql).captures[0]
end
对于冲突部分,您可以执行以下操作:
def on_conflict_statement(conflict_fields)
return ';' if conflict_fields.blank?
"ON CONFLICT (#{conflict_fields.join(', ')}) DO NOTHING"
end
最后,将它们全部串联在一起执行:
def perform(active_records:, conflict_fields:)
return if active_records.empty?
ActiveRecord::Base.connection.execute(
<<-SQL.squish
#{insert_statement(active_records.first)}
#{values(active_records)}
#{on_conflict_statement(conflict_fields)}
SQL
)
end
您可以检查here的最终解决方案。
这是我的输出-使用我的 balance 活动记录模型并删除执行SQL(ActiveRecord::Base.connection.execute...
)的代码段:
> puts BatchCreate.perform(active_records: [balance], conflict_fields: [:bank_account_id, :date])
INSERT INTO "balances" ("amount", "created_at", "currency", "date", "id", "bank_account_id", "updated_at") VALUES (0, '2018-11-28 15:42:44.312954', 'MXN', '2018-11-28', 15169, 26300, '2018-11-28 16:05:07.465402') ON CONFLICT (bank_account_id, date) DO NOTHING