我正在尝试使用activerecord-import导入数据,但我遇到了一个问题。如果该行已存在,则需要更新其他需要创建的行。表中的唯一行由两列的组合定义,其中每个列值在表中可能不唯一。我将如何使用on_duplicate_key_update的conflict_target,因为列不是唯一列。
现在了解详情。我有一个名为Order的模型,下面是Order模型中列的简化版本。
id
order_number
sku_number
quantity
数据库中的唯一行由order_number和sku_number的组合标识。 id列自动递增。通常情况下,如果我有一个唯一的列作为标识符,我可以执行以下操作。因此,在下面的示例中,我将使用id列作为conflict_target,假设id列是唯一标识符。
order = Order.create(order_number: '1', sku_number: '1', quantity: 100)
order.quantity = 200
Order.import [order], on_duplicate_key_update: {conflict_target: [:id], columns: [:quantity]}
这会更新数量,因为订单已经存在。
但我需要的是像
Order.import [order], on_duplicate_key_update: {conflict_target: [:order_number, :sku_number], columns: [:quantity]}
order_number和sku_number将唯一标识冲突行。
但由于Postgres期望为conflict_target提供一个独特的列,因此失败了。
有没有办法用非唯一列调用on_duplicate_key_update,即order_number和sku_number?
非常感谢任何帮助。
答案 0 :(得分:3)
我明白了。我正在制定解决方案以防其他人遇到同样的问题。
我最终在Order
上创建了一个唯一索引class AddUniqueKeyConstraintToOrders < ActiveRecord::Migration
def change
add_index :orders, [:order_number, :sku_number], unique: true
end
end
activerecord-import支持使用索引作为约束。所以我最终做了像
这样的事情order = Order.last
order.quantity = 200
Order.import [order], on_duplicate_key_update: {conflict_target: [:order_number, :sku_number], index_name: :index_orders_on_order_number_and_sku_number, columns: [:quantity]}
其中index_orders_on_order_number_and_sku_number是迁移创建的索引的名称。其中将数量从之前的值更新为200而不创建其他记录。
答案 1 :(得分:0)
另一种方法是将CONSTRAIANT创建为多列的唯一组合。在create_table之后的迁移文件中,我们可以:
create_table :board_statistics do |t|
t.string :hostname, null: false
t.string :slot
…
end
只创建一个唯一索引
add_index :board_statistics, [:hostname, :slot, :serial_number], unique: true
或创建约束
execute <<-SQL
ALTER TABLE board_statistics
ADD CONSTRAINT one_card_xan_slot UNIQUE (hostname, slot, serial_number);
SQL
Constraint可以在Activerecord-import gem中使用,如:
BoardStatistic.import columns, on_duplicate_key_ignore: {constraint_name: :one_card_xan_slot}